From 7bddd4a118ea2a56c631edd43e17f7b24ec677f9 Mon Sep 17 00:00:00 2001 From: glihm Date: Thu, 21 Mar 2024 20:57:33 -0600 Subject: [PATCH 1/6] fix: ensure sozo clean only affect base (#1685) The overlays are managed by the user. We don't want to clean them. The deployments are only output, and can't cause any conflict. For this reason, only base should be clean. --- bin/sozo/src/commands/clean.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/sozo/src/commands/clean.rs b/bin/sozo/src/commands/clean.rs index 5d0b12b0ff..0398c545a7 100644 --- a/bin/sozo/src/commands/clean.rs +++ b/bin/sozo/src/commands/clean.rs @@ -3,7 +3,7 @@ use std::fs; use anyhow::Result; use camino::Utf8PathBuf; use clap::Args; -use dojo_lang::compiler::{ABIS_DIR, MANIFESTS_DIR}; +use dojo_lang::compiler::{ABIS_DIR, BASE_DIR, MANIFESTS_DIR}; use scarb::core::Config; #[derive(Debug, Args)] @@ -21,15 +21,15 @@ pub struct CleanArgs { impl CleanArgs { pub fn clean_manifests_abis(&self, root_dir: &Utf8PathBuf) -> Result<()> { - let manifest_dir = root_dir.join(MANIFESTS_DIR); - let abis_dir = root_dir.join(ABIS_DIR); - - if manifest_dir.exists() { - fs::remove_dir_all(manifest_dir)?; - } - - if abis_dir.exists() { - fs::remove_dir_all(abis_dir)?; + let dirs = vec![ + root_dir.join(MANIFESTS_DIR).join(BASE_DIR), + root_dir.join(ABIS_DIR).join(BASE_DIR), + ]; + + for d in dirs { + if d.exists() { + fs::remove_dir_all(d)?; + } } Ok(()) From 810b0f45739d96f865fb6e402a30f4e3cf99a977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Baranx?= Date: Sun, 24 Mar 2024 01:28:37 +0700 Subject: [PATCH 2/6] sozo: add dry-run mode (#1686) --- bin/sozo/src/commands/migrate.rs | 3 +- crates/sozo/ops/src/migration/mod.rs | 142 +++++++++++++++++++++------ 2 files changed, 115 insertions(+), 30 deletions(-) diff --git a/bin/sozo/src/commands/migrate.rs b/bin/sozo/src/commands/migrate.rs index b8566d658d..5690a21936 100644 --- a/bin/sozo/src/commands/migrate.rs +++ b/bin/sozo/src/commands/migrate.rs @@ -119,7 +119,8 @@ impl MigrateArgs { ) .await?; - migration::migrate(&ws, world_address, chain_id, &account, self.name).await + migration::migrate(&ws, world_address, chain_id, &account, self.name, self.dry_run) + .await }) } } diff --git a/crates/sozo/ops/src/migration/mod.rs b/crates/sozo/ops/src/migration/mod.rs index 781d330dcb..7c93ac4a6a 100644 --- a/crates/sozo/ops/src/migration/mod.rs +++ b/crates/sozo/ops/src/migration/mod.rs @@ -21,8 +21,13 @@ use dojo_world::utils::TransactionWaiter; use scarb::core::Workspace; use scarb_ui::Ui; use starknet::accounts::{Account, ConnectedAccount, SingleOwnerAccount}; -use starknet::core::types::{FieldElement, InvokeTransactionResult}; -use starknet::core::utils::{cairo_short_string_to_felt, get_contract_address}; +use starknet::core::types::{ + BlockId, BlockTag, FieldElement, FunctionCall, InvokeTransactionResult, StarknetError, +}; +use starknet::core::utils::{ + cairo_short_string_to_felt, get_contract_address, get_selector_from_name, +}; +use starknet::providers::{Provider, ProviderError}; use tokio::fs; #[cfg(test)] @@ -30,7 +35,6 @@ use tokio::fs; mod migration_test; mod ui; -use starknet::providers::Provider; use starknet::signers::Signer; use ui::MigrationUi; @@ -52,6 +56,7 @@ pub async fn migrate( chain_id: String, account: &SingleOwnerAccount, name: Option, + dry_run: bool, ) -> Result<()> where P: Provider + Sync + Send + 'static, @@ -92,32 +97,36 @@ where let strategy = prepare_migration(&target_dir, diff, name.clone(), world_address, &ui)?; let world_address = strategy.world_address().expect("world address must exist"); - // Migrate according to the diff. - match apply_diff(ws, account, None, &strategy).await { - Ok(migration_output) => { - update_manifests_and_abis( - ws, - local_manifest, - remote_manifest, - &manifest_dir, - migration_output, - &chain_id, - name.as_ref(), - ) - .await?; - } - Err(e) => { - update_manifests_and_abis( - ws, - local_manifest, - remote_manifest, - &manifest_dir, - MigrationOutput { world_address, ..Default::default() }, - &chain_id, - name.as_ref(), - ) - .await?; - return Err(e)?; + if dry_run { + print_strategy(&ui, account.provider(), &strategy).await; + } else { + // Migrate according to the diff. + match apply_diff(ws, account, None, &strategy).await { + Ok(migration_output) => { + update_manifests_and_abis( + ws, + local_manifest, + remote_manifest, + &manifest_dir, + migration_output, + &chain_id, + name.as_ref(), + ) + .await?; + } + Err(e) => { + update_manifests_and_abis( + ws, + local_manifest, + remote_manifest, + &manifest_dir, + MigrationOutput { world_address, ..Default::default() }, + &chain_id, + name.as_ref(), + ) + .await?; + return Err(e)?; + } } }; @@ -683,3 +692,78 @@ pub fn handle_artifact_error(ui: &Ui, artifact_path: &Path, error: anyhow::Error --artifacts` to clean artifacts only.\nThen, rebuild your project with `sozo build`." ) } + +pub async fn get_contract_operation_name

( + provider: &P, + contract: &ContractMigration, + world_address: Option, +) -> String +where + P: Provider + Sync + Send + 'static, +{ + if let Some(world_address) = world_address { + if let Ok(base_class_hash) = provider + .call( + FunctionCall { + contract_address: world_address, + calldata: vec![], + entry_point_selector: get_selector_from_name("base").unwrap(), + }, + BlockId::Tag(BlockTag::Pending), + ) + .await + { + let contract_address = + get_contract_address(contract.salt, base_class_hash[0], &[], world_address); + + match provider + .get_class_hash_at(BlockId::Tag(BlockTag::Pending), contract_address) + .await + { + Ok(current_class_hash) if current_class_hash != contract.diff.local => { + return format!("upgrade {}", contract.diff.name); + } + Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) => { + return format!("deploy {}", contract.diff.name); + } + Ok(_) => return "already deployed".to_string(), + Err(_) => return format!("deploy {}", contract.diff.name), + } + } + } + format!("deploy {}", contract.diff.name) +} + +pub async fn print_strategy

(ui: &Ui, provider: &P, strategy: &MigrationStrategy) +where + P: Provider + Sync + Send + 'static, +{ + ui.print("\nšŸ“‹ Migration Strategy\n"); + + if let Some(base) = &strategy.base { + ui.print_header("# Base Contract"); + ui.print_sub(format!("declare (class hash: {:#x})\n", base.diff.local)); + } + + if let Some(world) = &strategy.world { + ui.print_header("# World"); + ui.print_sub(format!("declare (class hash: {:#x})\n", world.diff.local)); + } + + if !&strategy.models.is_empty() { + ui.print_header(format!("# Models ({})", &strategy.models.len())); + for m in &strategy.models { + ui.print_sub(format!("register {} (class hash: {:#x})", m.diff.name, m.diff.local)); + } + ui.print(" "); + } + + if !&strategy.contracts.is_empty() { + ui.print_header(format!("# Contracts ({})", &strategy.contracts.len())); + for c in &strategy.contracts { + let op_name = get_contract_operation_name(provider, c, strategy.world_address).await; + ui.print_sub(format!("{op_name} (class hash: {:#x})", c.diff.local)); + } + ui.print(" "); + } +} From 13990411f2dd05efecd034c107b4cd9f3994ae97 Mon Sep 17 00:00:00 2001 From: akhercha Date: Mon, 25 Mar 2024 18:37:59 +0100 Subject: [PATCH 3/6] feat(torii): Expose block timestamp (#1676) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(torii_block_timestamp): first work - Added some TODOs * feat(torii_block_timestamp): Ongoing reading - added TODOs * feat(torii_block_timestamp): Usage of block_timestamp in progress. * feat(torii_block_timestamp): Removed indexers timestamps createdAt + updatedAt for executedAt * feat(torii_block_timestamp): CI re-trigger * feat(torii_block_timestamp): Fixing bugs in progress * feat(torii_block_timestamp): Reverted last change - safe state working * feat(torii_block_timestamp): Removed updated_at & renamed created_at by executed_at * feat(torii_block_timestamp): Fixed SQL error * feat(torii_block_timestamp): Fixed created_at misses * feat(torii_block_timestamp): Slow update to check the CI * feat(torii_block_timestamp): Re-added created_at/updated_at + Check CI * feat(torii_block_timestamp): CI should pass šŸ˜Ø * feat(torii_block_timestamp): Merge with main + adapted test * feat(torii_block_timestamp): CI Trigger * feat(torii_block_timestamp): Removed TODO in SQL migration * feat(torii_block_timestamp): Fixed conflicts * feat(torii_block_timestamp): Removed executed_at for update_metadata * feat(torii_block_timestamp): Updated arguments order to align with other functions --- Cargo.lock | 1 + crates/torii/core/src/engine.rs | 57 +++++-- crates/torii/core/src/lib.rs | 1 + .../core/src/processors/event_message.rs | 3 +- .../core/src/processors/metadata_update.rs | 3 +- crates/torii/core/src/processors/mod.rs | 4 + .../core/src/processors/register_model.rs | 13 +- .../core/src/processors/store_del_record.rs | 1 + .../core/src/processors/store_set_record.rs | 3 +- .../core/src/processors/store_transaction.rs | 4 +- crates/torii/core/src/sql.rs | 152 ++++++++++++------ crates/torii/core/src/sql_test.rs | 14 +- crates/torii/core/src/types.rs | 3 + crates/torii/core/src/utils.rs | 46 ++++++ crates/torii/graphql/src/mapping.rs | 20 +++ crates/torii/graphql/src/object/entity.rs | 4 + crates/torii/graphql/src/object/event.rs | 4 + crates/torii/graphql/src/object/model.rs | 4 + crates/torii/graphql/src/object/model_data.rs | 1 + crates/torii/graphql/src/query/mod.rs | 1 + crates/torii/graphql/src/tests/events_test.rs | 4 + .../graphql/src/tests/fixtures/events.sql | 6 +- .../torii/graphql/src/tests/metadata_test.rs | 4 +- crates/torii/graphql/src/tests/mod.rs | 4 + .../graphql/src/tests/subscription_test.rs | 17 +- crates/torii/libp2p/Cargo.toml | 1 + crates/torii/libp2p/src/server/mod.rs | 17 +- .../torii/migrations/20230316154230_setup.sql | 6 + ...20231030154053_remove_syscalls_add_txn.sql | 1 + .../20231127235011_entity_model.sql | 5 +- .../migrations/20240314182410_event_model.sql | 1 + 31 files changed, 326 insertions(+), 79 deletions(-) create mode 100644 crates/torii/core/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index ba897b4e69..0da22cf1de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12678,6 +12678,7 @@ version = "0.6.0-alpha.7" dependencies = [ "anyhow", "async-trait", + "chrono", "crypto-bigint", "dojo-types", "dojo-world", diff --git a/crates/torii/core/src/engine.rs b/crates/torii/core/src/engine.rs index aad30273ca..b24bb49b73 100644 --- a/crates/torii/core/src/engine.rs +++ b/crates/torii/core/src/engine.rs @@ -3,8 +3,8 @@ use std::time::Duration; use anyhow::Result; use dojo_world::contracts::world::WorldContractReader; use starknet::core::types::{ - BlockId, EmittedEvent, Event, EventFilter, MaybePendingTransactionReceipt, Transaction, - TransactionReceipt, + BlockId, EmittedEvent, Event, EventFilter, MaybePendingBlockWithTxHashes, + MaybePendingTransactionReceipt, Transaction, TransactionReceipt, }; use starknet::core::utils::get_selector_from_name; use starknet::providers::Provider; @@ -154,6 +154,13 @@ impl Engine

{ Ok(()) } + async fn get_block_timestamp(&self, block_number: u64) -> Result { + match self.provider.get_block_with_tx_hashes(BlockId::Number(block_number)).await? { + MaybePendingBlockWithTxHashes::Block(block) => Ok(block.timestamp), + MaybePendingBlockWithTxHashes::PendingBlock(block) => Ok(block.timestamp), + } + } + async fn process(&mut self, event: EmittedEvent, last_block: &mut u64) -> Result<()> { let block_number = match event.block_number { Some(block_number) => block_number, @@ -162,6 +169,7 @@ impl Engine

{ return Ok(()); } }; + let block_timestamp = self.get_block_timestamp(block_number).await?; if block_number > *last_block { *last_block = block_number; @@ -170,15 +178,21 @@ impl Engine

{ block_tx.send(block_number).await?; } - Self::process_block(self, block_number, event.block_hash.unwrap()).await?; + Self::process_block(self, block_number, block_timestamp, event.block_hash.unwrap()) + .await?; info!(target: "torii_core::engine", block_number = %block_number, "Processed block"); self.db.set_head(block_number); } let transaction = self.provider.get_transaction_by_hash(event.transaction_hash).await?; - self.process_transaction_and_receipt(event.transaction_hash, &transaction, block_number) - .await?; + self.process_transaction_and_receipt( + event.transaction_hash, + &transaction, + block_number, + block_timestamp, + ) + .await?; Ok(()) } @@ -188,6 +202,7 @@ impl Engine

{ transaction_hash: FieldElement, transaction: &Transaction, block_number: u64, + block_timestamp: u64, ) -> Result<()> { let receipt = match self.provider.get_transaction_receipt(transaction_hash).await { Ok(receipt) => match receipt { @@ -222,13 +237,22 @@ impl Engine

{ let event_id = format!("{:#064x}:{:#x}:{:#04x}", block_number, transaction_hash, event_idx); - Self::process_event(self, block_number, &receipt, &event_id, event).await?; + Self::process_event( + self, + block_number, + block_timestamp, + &receipt, + &event_id, + event, + ) + .await?; } if world_event { Self::process_transaction( self, block_number, + block_timestamp, &receipt, transaction_hash, transaction, @@ -240,10 +264,21 @@ impl Engine

{ Ok(()) } - async fn process_block(&mut self, block_number: u64, block_hash: FieldElement) -> Result<()> { + async fn process_block( + &mut self, + block_number: u64, + block_timestamp: u64, + block_hash: FieldElement, + ) -> Result<()> { for processor in &self.processors.block { processor - .process(&mut self.db, self.provider.as_ref(), block_number, block_hash) + .process( + &mut self.db, + self.provider.as_ref(), + block_number, + block_timestamp, + block_hash, + ) .await?; } Ok(()) @@ -252,6 +287,7 @@ impl Engine

{ async fn process_transaction( &mut self, block_number: u64, + block_timestamp: u64, transaction_receipt: &TransactionReceipt, transaction_hash: FieldElement, transaction: &Transaction, @@ -262,6 +298,7 @@ impl Engine

{ &mut self.db, self.provider.as_ref(), block_number, + block_timestamp, transaction_receipt, transaction_hash, transaction, @@ -275,6 +312,7 @@ impl Engine

{ async fn process_event( &mut self, block_number: u64, + block_timestamp: u64, transaction_receipt: &TransactionReceipt, event_id: &str, event: &Event, @@ -286,7 +324,7 @@ impl Engine

{ } _ => return Ok(()), }; - self.db.store_event(event_id, event, transaction_hash); + self.db.store_event(event_id, event, transaction_hash, block_timestamp); for processor in &self.processors.event { // If the processor has no event_key, means it's a catch-all processor. // We also validate the event @@ -299,6 +337,7 @@ impl Engine

{ &self.world, &mut self.db, block_number, + block_timestamp, transaction_receipt, event_id, event, diff --git a/crates/torii/core/src/lib.rs b/crates/torii/core/src/lib.rs index e36c3f2e3b..abd0af414a 100644 --- a/crates/torii/core/src/lib.rs +++ b/crates/torii/core/src/lib.rs @@ -12,6 +12,7 @@ pub mod query_queue; pub mod simple_broker; pub mod sql; pub mod types; +pub mod utils; #[allow(dead_code)] #[derive(FromRow, Deserialize)] diff --git a/crates/torii/core/src/processors/event_message.rs b/crates/torii/core/src/processors/event_message.rs index c83a35930a..ce68f574ba 100644 --- a/crates/torii/core/src/processors/event_message.rs +++ b/crates/torii/core/src/processors/event_message.rs @@ -39,6 +39,7 @@ where _world: &WorldContractReader

, db: &mut Sql, _block_number: u64, + block_timestamp: u64, _transaction_receipt: &TransactionReceipt, event_id: &str, event: &Event, @@ -59,7 +60,7 @@ where let mut entity = model.schema().await?; entity.deserialize(&mut keys_and_unpacked)?; - db.set_event_message(entity, event_id).await?; + db.set_event_message(entity, event_id, block_timestamp).await?; Ok(()) } } diff --git a/crates/torii/core/src/processors/metadata_update.rs b/crates/torii/core/src/processors/metadata_update.rs index 2e94ccd0c8..2df4ac4e9a 100644 --- a/crates/torii/core/src/processors/metadata_update.rs +++ b/crates/torii/core/src/processors/metadata_update.rs @@ -49,6 +49,7 @@ where _world: &WorldContractReader

, db: &mut Sql, _block_number: u64, + block_timestamp: u64, _transaction_receipt: &TransactionReceipt, _event_id: &str, event: &Event, @@ -67,7 +68,7 @@ where }; info!("Resource {:#x} metadata set: {}", resource, uri_str); - db.set_metadata(resource, &uri_str); + db.set_metadata(resource, &uri_str, block_timestamp); let db = db.clone(); let resource = *resource; diff --git a/crates/torii/core/src/processors/mod.rs b/crates/torii/core/src/processors/mod.rs index 1d12817655..f40ff90fdd 100644 --- a/crates/torii/core/src/processors/mod.rs +++ b/crates/torii/core/src/processors/mod.rs @@ -36,6 +36,7 @@ where world: &WorldContractReader

, db: &mut Sql, block_number: u64, + block_timestamp: u64, transaction_receipt: &TransactionReceipt, event_id: &str, event: &Event, @@ -50,17 +51,20 @@ pub trait BlockProcessor { db: &mut Sql, provider: &P, block_number: u64, + block_timestamp: u64, block_hash: FieldElement, ) -> Result<(), Error>; } #[async_trait] pub trait TransactionProcessor { + #[allow(clippy::too_many_arguments)] async fn process( &self, db: &mut Sql, provider: &P, block_number: u64, + block_timestamp: u64, transaction_receipt: &TransactionReceipt, transaction_hash: FieldElement, transaction: &Transaction, diff --git a/crates/torii/core/src/processors/register_model.rs b/crates/torii/core/src/processors/register_model.rs index fd2f14b8dc..f5facb99e5 100644 --- a/crates/torii/core/src/processors/register_model.rs +++ b/crates/torii/core/src/processors/register_model.rs @@ -39,6 +39,7 @@ where world: &WorldContractReader

, db: &mut Sql, _block_number: u64, + block_timestamp: u64, _transaction_receipt: &TransactionReceipt, _event_id: &str, event: &Event, @@ -67,8 +68,16 @@ where "Registered model content" ); - db.register_model(schema, layout, class_hash, contract_address, packed_size, unpacked_size) - .await?; + db.register_model( + schema, + layout, + class_hash, + contract_address, + packed_size, + unpacked_size, + block_timestamp, + ) + .await?; Ok(()) } diff --git a/crates/torii/core/src/processors/store_del_record.rs b/crates/torii/core/src/processors/store_del_record.rs index 26d5272148..f889a45517 100644 --- a/crates/torii/core/src/processors/store_del_record.rs +++ b/crates/torii/core/src/processors/store_del_record.rs @@ -40,6 +40,7 @@ where _world: &WorldContractReader

, db: &mut Sql, _block_number: u64, + _block_timestamp: u64, _transaction_receipt: &TransactionReceipt, _event_id: &str, event: &Event, diff --git a/crates/torii/core/src/processors/store_set_record.rs b/crates/torii/core/src/processors/store_set_record.rs index e5379464d6..428f31858f 100644 --- a/crates/torii/core/src/processors/store_set_record.rs +++ b/crates/torii/core/src/processors/store_set_record.rs @@ -40,6 +40,7 @@ where _world: &WorldContractReader

, db: &mut Sql, _block_number: u64, + block_timestamp: u64, _transaction_receipt: &TransactionReceipt, event_id: &str, event: &Event, @@ -65,7 +66,7 @@ where let mut entity = model.schema().await?; entity.deserialize(&mut keys_and_unpacked)?; - db.set_entity(entity, event_id).await?; + db.set_entity(entity, event_id, block_timestamp).await?; Ok(()) } } diff --git a/crates/torii/core/src/processors/store_transaction.rs b/crates/torii/core/src/processors/store_transaction.rs index 3caf2c7654..448de5f6ff 100644 --- a/crates/torii/core/src/processors/store_transaction.rs +++ b/crates/torii/core/src/processors/store_transaction.rs @@ -17,13 +17,13 @@ impl TransactionProcessor

for StoreTransactionProcessor { db: &mut Sql, _provider: &P, block_number: u64, + block_timestamp: u64, _receipt: &TransactionReceipt, transaction_hash: FieldElement, transaction: &Transaction, ) -> Result<(), Error> { let transaction_id = format!("{:#064x}:{:#x}", block_number, transaction_hash); - db.store_transaction(transaction, &transaction_id); - + db.store_transaction(transaction, &transaction_id, block_timestamp); Ok(()) } } diff --git a/crates/torii/core/src/sql.rs b/crates/torii/core/src/sql.rs index d0a406040e..1dc24e454d 100644 --- a/crates/torii/core/src/sql.rs +++ b/crates/torii/core/src/sql.rs @@ -17,6 +17,7 @@ use crate::model::ModelSQLReader; use crate::query_queue::{Argument, QueryQueue}; use crate::simple_broker::SimpleBroker; use crate::types::{Entity as EntityUpdated, Event as EventEmitted, Model as ModelRegistered}; +use crate::utils::{must_utc_datetime_from_timestamp, utc_dt_string_from_timestamp}; pub const FELT_DELIMITER: &str = "/"; @@ -75,6 +76,7 @@ impl Sql { Ok(meta) } + #[allow(clippy::too_many_arguments)] pub async fn register_model( &mut self, model: Ty, @@ -83,6 +85,7 @@ impl Sql { contract_address: FieldElement, packed_size: u32, unpacked_size: u32, + block_timestamp: u64, ) -> Result<()> { let layout_blob = layout .iter() @@ -91,10 +94,11 @@ impl Sql { let insert_models = "INSERT INTO models (id, name, class_hash, contract_address, layout, packed_size, \ - unpacked_size) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET \ - contract_address=EXCLUDED.contract_address, class_hash=EXCLUDED.class_hash, \ - layout=EXCLUDED.layout, packed_size=EXCLUDED.packed_size, \ - unpacked_size=EXCLUDED.unpacked_size RETURNING *"; + unpacked_size, executed_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO \ + UPDATE SET contract_address=EXCLUDED.contract_address, \ + class_hash=EXCLUDED.class_hash, layout=EXCLUDED.layout, \ + packed_size=EXCLUDED.packed_size, unpacked_size=EXCLUDED.unpacked_size, \ + executed_at=EXCLUDED.executed_at RETURNING *"; let model_registered: ModelRegistered = sqlx::query_as(insert_models) // this is temporary until the model hash is precomputed .bind(&format!("{:#x}", &get_selector_from_name(&model.name())?)) @@ -104,11 +108,17 @@ impl Sql { .bind(hex::encode(&layout_blob)) .bind(packed_size) .bind(unpacked_size) + .bind(utc_dt_string_from_timestamp(block_timestamp)) .fetch_one(&self.pool) .await?; let mut model_idx = 0_i64; - self.build_register_queries_recursive(&model, vec![model.name()], &mut model_idx); + self.build_register_queries_recursive( + &model, + vec![model.name()], + &mut model_idx, + block_timestamp, + ); self.query_queue.execute_all().await?; SimpleBroker::publish(model_registered); @@ -116,7 +126,12 @@ impl Sql { Ok(()) } - pub async fn set_entity(&mut self, entity: Ty, event_id: &str) -> Result<()> { + pub async fn set_entity( + &mut self, + entity: Ty, + event_id: &str, + block_timestamp: u64, + ) -> Result<()> { let keys = if let Ty::Struct(s) = &entity { let mut keys = Vec::new(); for m in s.keys() { @@ -138,18 +153,27 @@ impl Sql { ); let keys_str = felts_sql_string(&keys); - let insert_entities = "INSERT INTO entities (id, keys, event_id) VALUES (?, ?, ?) ON \ - CONFLICT(id) DO UPDATE SET updated_at=CURRENT_TIMESTAMP, \ - event_id=EXCLUDED.event_id RETURNING *"; + let insert_entities = "INSERT INTO entities (id, keys, event_id, executed_at) VALUES (?, \ + ?, ?, ?) ON CONFLICT(id) DO UPDATE SET \ + executed_at=EXCLUDED.executed_at, event_id=EXCLUDED.event_id \ + RETURNING *"; let entity_updated: EntityUpdated = sqlx::query_as(insert_entities) .bind(&entity_id) .bind(&keys_str) .bind(event_id) + .bind(utc_dt_string_from_timestamp(block_timestamp)) .fetch_one(&self.pool) .await?; let path = vec![entity.name()]; - self.build_set_entity_queries_recursive(path, event_id, &entity_id, &entity, false); + self.build_set_entity_queries_recursive( + path, + event_id, + &entity_id, + &entity, + block_timestamp, + false, + ); self.query_queue.execute_all().await?; SimpleBroker::publish(entity_updated); @@ -157,7 +181,12 @@ impl Sql { Ok(()) } - pub async fn set_event_message(&mut self, entity: Ty, event_id: &str) -> Result<()> { + pub async fn set_event_message( + &mut self, + entity: Ty, + event_id: &str, + block_timestamp: u64, + ) -> Result<()> { let keys = if let Ty::Struct(s) = &entity { let mut keys = Vec::new(); for m in s.keys() { @@ -179,18 +208,27 @@ impl Sql { ); let keys_str = felts_sql_string(&keys); - let insert_entities = "INSERT INTO event_messages (id, keys, event_id) VALUES (?, ?, ?) \ - ON CONFLICT(id) DO UPDATE SET updated_at=CURRENT_TIMESTAMP, \ - event_id=EXCLUDED.event_id RETURNING *"; + let insert_entities = "INSERT INTO event_messages (id, keys, event_id, executed_at) \ + VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET \ + updated_at=CURRENT_TIMESTAMP, event_id=EXCLUDED.event_id RETURNING \ + *"; let entity_updated: EntityUpdated = sqlx::query_as(insert_entities) .bind(&entity_id) .bind(&keys_str) .bind(event_id) + .bind(utc_dt_string_from_timestamp(block_timestamp)) .fetch_one(&self.pool) .await?; let path = vec![entity.name()]; - self.build_set_entity_queries_recursive(path, event_id, &entity_id, &entity, true); + self.build_set_entity_queries_recursive( + path, + event_id, + &entity_id, + &entity, + block_timestamp, + true, + ); self.query_queue.execute_all().await?; SimpleBroker::publish(entity_updated); @@ -206,14 +244,16 @@ impl Sql { Ok(()) } - pub fn set_metadata(&mut self, resource: &FieldElement, uri: &str) { + pub fn set_metadata(&mut self, resource: &FieldElement, uri: &str, block_timestamp: u64) { let resource = Argument::FieldElement(*resource); let uri = Argument::String(uri.to_string()); + let executed_at = Argument::String(utc_dt_string_from_timestamp(block_timestamp)); self.query_queue.enqueue( - "INSERT INTO metadata (id, uri) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET \ - id=excluded.id, updated_at=CURRENT_TIMESTAMP", - vec![resource, uri], + "INSERT INTO metadata (id, uri, executed_at) VALUES (?, ?, ?) ON CONFLICT(id) DO \ + UPDATE SET id=excluded.id, executed_at=excluded.executed_at, \ + updated_at=CURRENT_TIMESTAMP", + vec![resource, uri, executed_at], ); } @@ -227,34 +267,21 @@ impl Sql { ) -> Result<()> { let json = serde_json::to_string(metadata).unwrap(); // safe unwrap - let mut columns = vec!["id", "uri", "json"]; - let mut update = - vec!["id=excluded.id", "json=excluded.json", "updated_at=CURRENT_TIMESTAMP"]; - let mut arguments = vec![ - Argument::FieldElement(*resource), - Argument::String(uri.to_string()), - Argument::String(json), - ]; + let mut update = vec!["uri=?", "json=?", "updated_at=CURRENT_TIMESTAMP"]; + let mut arguments = vec![Argument::String(uri.to_string()), Argument::String(json)]; if let Some(icon) = icon_img { - columns.push("icon_img"); + update.push("icon_img=?"); arguments.push(Argument::String(icon.clone())); - update.push("icon_img=excluded.icon_img"); } if let Some(cover) = cover_img { - columns.push("cover_img"); + update.push("cover_img=?"); arguments.push(Argument::String(cover.clone())); - update.push("cover_img=excluded.cover_img"); } - let placeholders: Vec<&str> = arguments.iter().map(|_| "?").collect(); - let statement = format!( - "INSERT INTO metadata ({}) VALUES ({}) ON CONFLICT(id) DO UPDATE SET {}", - columns.join(","), - placeholders.join(","), - update.join(",") - ); + let statement = format!("UPDATE metadata SET {} WHERE id = ?", update.join(",")); + arguments.push(Argument::FieldElement(*resource)); self.query_queue.enqueue(statement, arguments); self.query_queue.execute_all().await?; @@ -284,7 +311,12 @@ impl Sql { Ok(rows.drain(..).map(|row| serde_json::from_str(&row.2).unwrap()).collect()) } - pub fn store_transaction(&mut self, transaction: &Transaction, transaction_id: &str) { + pub fn store_transaction( + &mut self, + transaction: &Transaction, + transaction_id: &str, + block_timestamp: u64, + ) { let id = Argument::String(transaction_id.to_string()); let transaction_type = match transaction { @@ -316,7 +348,8 @@ impl Sql { self.query_queue.enqueue( "INSERT OR IGNORE INTO transactions (id, transaction_hash, sender_address, calldata, \ - max_fee, signature, nonce, transaction_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + max_fee, signature, nonce, transaction_type, executed_at) VALUES (?, ?, ?, ?, ?, ?, \ + ?, ?, ?)", vec![ id, transaction_hash, @@ -326,19 +359,28 @@ impl Sql { signature, nonce, Argument::String(transaction_type.to_string()), + Argument::String(utc_dt_string_from_timestamp(block_timestamp)), ], ); } - pub fn store_event(&mut self, event_id: &str, event: &Event, transaction_hash: FieldElement) { + pub fn store_event( + &mut self, + event_id: &str, + event: &Event, + transaction_hash: FieldElement, + block_timestamp: u64, + ) { let id = Argument::String(event_id.to_string()); let keys = Argument::String(felts_sql_string(&event.keys)); let data = Argument::String(felts_sql_string(&event.data)); let hash = Argument::FieldElement(transaction_hash); + let executed_at = Argument::String(utc_dt_string_from_timestamp(block_timestamp)); self.query_queue.enqueue( - "INSERT OR IGNORE INTO events (id, keys, data, transaction_hash) VALUES (?, ?, ?, ?)", - vec![id, keys, data, hash], + "INSERT OR IGNORE INTO events (id, keys, data, transaction_hash, executed_at) VALUES \ + (?, ?, ?, ?, ?)", + vec![id, keys, data, hash, executed_at], ); SimpleBroker::publish(EventEmitted { @@ -347,6 +389,7 @@ impl Sql { data: felts_sql_string(&event.data), transaction_hash: format!("{:#x}", transaction_hash), created_at: Utc::now(), + executed_at: must_utc_datetime_from_timestamp(block_timestamp), }); } @@ -355,13 +398,14 @@ impl Sql { model: &Ty, path: Vec, model_idx: &mut i64, + block_timestamp: u64, ) { if let Ty::Enum(_) = model { // Complex enum values not supported yet. return; } - self.build_model_query(path.clone(), model, *model_idx); + self.build_model_query(path.clone(), model, *model_idx, block_timestamp); if let Ty::Struct(s) = model { for member in s.children.iter() { @@ -376,6 +420,7 @@ impl Sql { &member.ty, path_clone, &mut (*model_idx + 1), + block_timestamp, ); } } @@ -387,6 +432,7 @@ impl Sql { event_id: &str, entity_id: &str, entity: &Ty, + block_timestamp: u64, is_event_message: bool, ) { match entity { @@ -395,6 +441,7 @@ impl Sql { let mut columns = vec![ "id".to_string(), "event_id".to_string(), + "executed_at".to_string(), if is_event_message { "event_message_id".to_string() } else { @@ -408,6 +455,7 @@ impl Sql { entity_id.to_string() }), Argument::String(event_id.to_string()), + Argument::String(utc_dt_string_from_timestamp(block_timestamp)), Argument::String(entity_id.to_string()), ]; @@ -443,6 +491,7 @@ impl Sql { event_id, entity_id, &member.ty, + block_timestamp, is_event_message, ); } @@ -457,6 +506,7 @@ impl Sql { event_id, entity_id, &child.ty, + block_timestamp, is_event_message, ); } @@ -498,7 +548,13 @@ impl Sql { } } - fn build_model_query(&mut self, path: Vec, model: &Ty, model_idx: i64) { + fn build_model_query( + &mut self, + path: Vec, + model: &Ty, + model_idx: i64, + block_timestamp: u64, + ) { let table_id = path.join("$"); let mut indices = Vec::new(); @@ -547,8 +603,8 @@ impl Sql { } let statement = "INSERT OR IGNORE INTO model_members (id, model_id, model_idx, \ - member_idx, name, type, type_enum, enum_options, key) VALUES (?, \ - ?, ?, ?, ?, ?, ?, ?, ?)"; + member_idx, name, type, type_enum, enum_options, key, \ + executed_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; let arguments = vec![ Argument::String(table_id.clone()), // TEMP: this is temporary until the model hash is precomputed @@ -563,12 +619,14 @@ impl Sql { Argument::String(member.ty.as_ref().into()), options.unwrap_or(Argument::Null), Argument::Bool(member.key), + Argument::String(utc_dt_string_from_timestamp(block_timestamp)), ]; self.query_queue.enqueue(statement, arguments); } } + create_table_query.push_str("executed_at DATETIME NOT NULL, "); create_table_query.push_str("created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, "); // If this is not the Model's root table, create a reference to the parent. diff --git a/crates/torii/core/src/sql_test.rs b/crates/torii/core/src/sql_test.rs index 69c1b44a4d..cf6fbcd177 100644 --- a/crates/torii/core/src/sql_test.rs +++ b/crates/torii/core/src/sql_test.rs @@ -20,6 +20,7 @@ use crate::engine::{Engine, EngineConfig, Processors}; use crate::processors::register_model::RegisterModelProcessor; use crate::processors::store_set_record::StoreSetRecordProcessor; use crate::sql::Sql; +use crate::utils::utc_dt_string_from_timestamp; pub async fn bootstrap_engine

( world: WorldContractReader

, @@ -75,6 +76,7 @@ async fn test_load_from_remote() { let mut db = Sql::new(pool.clone(), migration.world_address().unwrap()).await.unwrap(); let _ = bootstrap_engine(world, db.clone(), &provider, migration, sequencer).await; + let block_timestamp = 1710754478_u64; let models = sqlx::query("SELECT * FROM models").fetch_all(&pool).await.unwrap(); assert_eq!(models.len(), 3); @@ -111,16 +113,20 @@ async fn test_load_from_remote() { data: Vec::from([FieldElement::TWO, FieldElement::THREE]), }, FieldElement::THREE, + block_timestamp, ); db.execute().await.unwrap(); - let query = - format!("SELECT keys, data, transaction_hash FROM events WHERE id = '{}'", event_id); - let (keys, data, tx_hash): (String, String, String) = + let query = format!( + "SELECT keys, data, transaction_hash, executed_at FROM events WHERE id = '{}'", + event_id + ); + let (keys, data, tx_hash, executed_at): (String, String, String, String) = sqlx::query_as(&query).fetch_one(&pool).await.unwrap(); assert_eq!(keys, format!("{:#x}/", FieldElement::TWO)); assert_eq!(data, format!("{:#x}/{:#x}/", FieldElement::TWO, FieldElement::THREE)); - assert_eq!(tx_hash, format!("{:#x}", FieldElement::THREE)) + assert_eq!(tx_hash, format!("{:#x}", FieldElement::THREE)); + assert_eq!(executed_at, utc_dt_string_from_timestamp(block_timestamp)); } diff --git a/crates/torii/core/src/types.rs b/crates/torii/core/src/types.rs index af4328b90e..0e0fc35cac 100644 --- a/crates/torii/core/src/types.rs +++ b/crates/torii/core/src/types.rs @@ -34,6 +34,7 @@ pub struct Entity { pub id: String, pub keys: String, pub event_id: String, + pub executed_at: DateTime, pub created_at: DateTime, pub updated_at: DateTime, } @@ -46,6 +47,7 @@ pub struct Model { pub class_hash: String, pub contract_address: String, pub transaction_hash: String, + pub executed_at: DateTime, pub created_at: DateTime, } @@ -56,5 +58,6 @@ pub struct Event { pub keys: String, pub data: String, pub transaction_hash: String, + pub executed_at: DateTime, pub created_at: DateTime, } diff --git a/crates/torii/core/src/utils.rs b/crates/torii/core/src/utils.rs new file mode 100644 index 0000000000..96e0adaaf0 --- /dev/null +++ b/crates/torii/core/src/utils.rs @@ -0,0 +1,46 @@ +use chrono::{DateTime, NaiveDateTime, Utc}; + +pub fn must_utc_datetime_from_timestamp(timestamp: u64) -> DateTime { + let naive_dt = NaiveDateTime::from_timestamp_opt(timestamp as i64, 0) + .expect("Failed to convert timestamp to NaiveDateTime"); + DateTime::::from_naive_utc_and_offset(naive_dt, Utc) +} + +pub fn utc_dt_string_from_timestamp(timestamp: u64) -> String { + must_utc_datetime_from_timestamp(timestamp).to_rfc3339() +} + +// tests +#[cfg(test)] +mod tests { + use chrono::{DateTime, NaiveDate, NaiveTime, Utc}; + + use super::*; + + #[test] + fn test_must_utc_datetime_from_timestamp() { + let timestamp = 1633027200; + let expected_date = NaiveDate::from_ymd_opt(2021, 9, 30).unwrap(); + let expected_time = NaiveTime::from_hms_opt(18, 40, 0).unwrap(); + let expected = + DateTime::::from_naive_utc_and_offset(expected_date.and_time(expected_time), Utc); + let out = must_utc_datetime_from_timestamp(timestamp); + assert_eq!(out, expected, "Failed to convert timestamp to DateTime"); + } + + #[test] + #[should_panic(expected = "Failed to convert timestamp to NaiveDateTime")] + fn test_must_utc_datetime_from_timestamp_incorrect_timestamp() { + let timestamp = i64::MAX as u64 + 1; + let _result = must_utc_datetime_from_timestamp(timestamp); + } + + #[test] + fn test_utc_dt_string_from_timestamp() { + let timestamp = 1633027200; + let expected = "2021-09-30T18:40:00+00:00"; + let out = utc_dt_string_from_timestamp(timestamp); + println!("{}", out); + assert_eq!(out, expected, "Failed to convert timestamp to String"); + } +} diff --git a/crates/torii/graphql/src/mapping.rs b/crates/torii/graphql/src/mapping.rs index 2aefccbd91..a3839a9f4a 100644 --- a/crates/torii/graphql/src/mapping.rs +++ b/crates/torii/graphql/src/mapping.rs @@ -12,6 +12,10 @@ lazy_static! { (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), (Name::new("keys"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), (Name::new("eventId"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + ( + Name::new("executedAt"), + TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), + ), ( Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), @@ -25,6 +29,10 @@ lazy_static! { (Name::new("id"), TypeData::Simple(TypeRef::named(TypeRef::ID))), (Name::new("keys"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), (Name::new("data"), TypeData::Simple(TypeRef::named_list(TypeRef::STRING))), + ( + Name::new("executedAt"), + TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), + ), ( Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), @@ -46,6 +54,10 @@ lazy_static! { Name::new("transactionHash"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())), ), + ( + Name::new("executedAt"), + TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), + ), ( Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), @@ -77,6 +89,10 @@ lazy_static! { Name::new("nonce"), TypeData::Simple(TypeRef::named(Primitive::Felt252(None).to_string())) ), + ( + Name::new("executedAt"), + TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), + ), ( Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), @@ -114,6 +130,10 @@ lazy_static! { ), (Name::new("iconImg"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), (Name::new("coverImg"), TypeData::Simple(TypeRef::named(TypeRef::STRING))), + ( + Name::new("executedAt"), + TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())), + ), ( Name::new("createdAt"), TypeData::Simple(TypeRef::named(GraphqlType::DateTime.to_string())) diff --git a/crates/torii/graphql/src/object/entity.rs b/crates/torii/graphql/src/object/entity.rs index d4f3f507f4..52d0f89494 100644 --- a/crates/torii/graphql/src/object/entity.rs +++ b/crates/torii/graphql/src/object/entity.rs @@ -102,6 +102,10 @@ impl EntityObject { Name::new("updatedAt"), Value::from(entity.updated_at.format(DATETIME_FORMAT).to_string()), ), + ( + Name::new("executedAt"), + Value::from(entity.executed_at.format(DATETIME_FORMAT).to_string()), + ), ]) } } diff --git a/crates/torii/graphql/src/object/event.rs b/crates/torii/graphql/src/object/event.rs index 8e37cab5ea..f0063f76c1 100644 --- a/crates/torii/graphql/src/object/event.rs +++ b/crates/torii/graphql/src/object/event.rs @@ -69,6 +69,10 @@ impl EventObject { Name::new("createdAt"), Value::from(event.created_at.format(DATETIME_FORMAT).to_string()), ), + ( + Name::new("executedAt"), + Value::from(event.executed_at.format(DATETIME_FORMAT).to_string()), + ), ]) } diff --git a/crates/torii/graphql/src/object/model.rs b/crates/torii/graphql/src/object/model.rs index 3dd84b8425..a9ecb13607 100644 --- a/crates/torii/graphql/src/object/model.rs +++ b/crates/torii/graphql/src/object/model.rs @@ -112,6 +112,10 @@ impl ModelObject { Name::new("createdAt"), Value::from(model.created_at.format(DATETIME_FORMAT).to_string()), ), + ( + Name::new("executedAt"), + Value::from(model.executed_at.format(DATETIME_FORMAT).to_string()), + ), ]) } } diff --git a/crates/torii/graphql/src/object/model_data.rs b/crates/torii/graphql/src/object/model_data.rs index 83263cd61b..943633aef8 100644 --- a/crates/torii/graphql/src/object/model_data.rs +++ b/crates/torii/graphql/src/object/model_data.rs @@ -28,6 +28,7 @@ pub struct ModelMember { pub ty: String, pub type_enum: String, pub key: bool, + pub executed_at: DateTime, pub created_at: DateTime, } diff --git a/crates/torii/graphql/src/query/mod.rs b/crates/torii/graphql/src/query/mod.rs index 9b5d617382..0f677b920a 100644 --- a/crates/torii/graphql/src/query/mod.rs +++ b/crates/torii/graphql/src/query/mod.rs @@ -42,6 +42,7 @@ async fn fetch_model_members( type AS ty, type_enum, key, + executed_at, created_at from model_members WHERE model_id = ? "#, diff --git a/crates/torii/graphql/src/tests/events_test.rs b/crates/torii/graphql/src/tests/events_test.rs index ccc654ac99..faabf9013d 100644 --- a/crates/torii/graphql/src/tests/events_test.rs +++ b/crates/torii/graphql/src/tests/events_test.rs @@ -21,6 +21,7 @@ mod tests { keys data transactionHash + executedAt }} }} pageInfo {{ @@ -55,18 +56,21 @@ mod tests { let event = connection.edges.first().unwrap(); assert_eq!(connection.total_count, 1); assert_eq!(event.node.id, "0x1"); + assert_eq!(event.node.executed_at, "2024-03-19T16:32:10+00:00"); let result = events_query(&schema, "(keys: [\"0x2\", \"*\", \"0x1\"])").await; let connection: Connection = serde_json::from_value(result.clone())?; let event = connection.edges.first().unwrap(); assert_eq!(connection.total_count, 1); assert_eq!(event.node.id, "0x2"); + assert_eq!(event.node.executed_at, "2024-03-19T16:32:10+00:00"); let result = events_query(&schema, "(keys: [\"*\", \"0x1\"])").await; let connection: Connection = serde_json::from_value(result.clone())?; let event = connection.edges.first().unwrap(); assert_eq!(connection.total_count, 1); assert_eq!(event.node.id, "0x3"); + assert_eq!(event.node.executed_at, "2024-03-19T16:32:10+00:00"); Ok(()) } diff --git a/crates/torii/graphql/src/tests/fixtures/events.sql b/crates/torii/graphql/src/tests/fixtures/events.sql index cd47d3cc6d..28752d3bf5 100644 --- a/crates/torii/graphql/src/tests/fixtures/events.sql +++ b/crates/torii/graphql/src/tests/fixtures/events.sql @@ -1,3 +1,3 @@ -INSERT INTO events (id, keys, data, transaction_hash) VALUES ('0x1', '0x1/0x2/0x3/', '0x1/', '0x123'); -INSERT INTO events (id, keys, data, transaction_hash) VALUES ('0x2', '0x2/0x3/0x1/', '0x2/', '0x123'); -INSERT INTO events (id, keys, data, transaction_hash) VALUES ('0x3', '0x3/0x1/0x2/', '0x3/', '0x123'); +INSERT INTO events (id, keys, data, transaction_hash, executed_at) VALUES ('0x1', '0x1/0x2/0x3/', '0x1/', '0x123', '2024-03-19T16:32:10+00:00'); +INSERT INTO events (id, keys, data, transaction_hash, executed_at) VALUES ('0x2', '0x2/0x3/0x1/', '0x2/', '0x123', '2024-03-19T16:32:10+00:00'); +INSERT INTO events (id, keys, data, transaction_hash, executed_at) VALUES ('0x3', '0x3/0x1/0x2/', '0x3/', '0x123', '2024-03-19T16:32:10+00:00'); diff --git a/crates/torii/graphql/src/tests/metadata_test.rs b/crates/torii/graphql/src/tests/metadata_test.rs index aa4714008d..01914abfb7 100644 --- a/crates/torii/graphql/src/tests/metadata_test.rs +++ b/crates/torii/graphql/src/tests/metadata_test.rs @@ -10,6 +10,7 @@ mod tests { const RESOURCE: FieldElement = FieldElement::ZERO; const URI: &str = "ipfs://QmcDVFdDph5N2AoW7L2vruyhy6A3wiU8Mh5hEyfVY68ynh"; + const BLOCK_TIMESTAMP: u64 = 1710754478; const QUERY: &str = r#" { metadatas { @@ -62,6 +63,7 @@ mod tests { ) .unwrap(); let world_metadata = dojo_metadata.world.unwrap(); + db.set_metadata(&RESOURCE, URI, BLOCK_TIMESTAMP); db.update_metadata(&RESOURCE, URI, &world_metadata, &None, &Some(cover_img.to_string())) .await .unwrap(); @@ -94,7 +96,7 @@ mod tests { let mut db = Sql::new(pool.clone(), FieldElement::ZERO).await.unwrap(); let schema = build_schema(&pool).await.unwrap(); - db.set_metadata(&RESOURCE, URI); + db.set_metadata(&RESOURCE, URI, BLOCK_TIMESTAMP); db.execute().await.unwrap(); let result = run_graphql_query(&schema, QUERY).await; diff --git a/crates/torii/graphql/src/tests/mod.rs b/crates/torii/graphql/src/tests/mod.rs index a96c72d240..f7ece5b498 100644 --- a/crates/torii/graphql/src/tests/mod.rs +++ b/crates/torii/graphql/src/tests/mod.rs @@ -68,6 +68,7 @@ pub struct Event { pub keys: Vec, pub data: Vec, pub transaction_hash: String, + pub executed_at: String, } #[derive(Deserialize, Debug, PartialEq)] @@ -188,6 +189,8 @@ pub struct Metadata { pub async fn run_graphql_query(schema: &Schema, query: &str) -> Value { let res = schema.execute(query).await; + println!("Trying to execute query: {}", query); + assert!(res.errors.is_empty(), "GraphQL query returned errors: {:?}", res.errors); serde_json::to_value(res.data).expect("Failed to serialize GraphQL response") } @@ -259,6 +262,7 @@ pub async fn model_fixtures(db: &mut Sql) { FieldElement::TWO, 0, 0, + 1710754478_u64, ) .await .unwrap(); diff --git a/crates/torii/graphql/src/tests/subscription_test.rs b/crates/torii/graphql/src/tests/subscription_test.rs index 5d6b1a94ed..2281639f4a 100644 --- a/crates/torii/graphql/src/tests/subscription_test.rs +++ b/crates/torii/graphql/src/tests/subscription_test.rs @@ -27,6 +27,7 @@ mod tests { let key = vec![FieldElement::ONE]; let entity_id = format!("{:#x}", poseidon_hash_many(&key)); let keys_str = key.iter().map(|k| format!("{:#x}", k)).collect::>().join(","); + let block_timestamp = 1710754478_u64; let expected_value: async_graphql::Value = value!({ "entityUpdated": { "id": entity_id, @@ -101,6 +102,7 @@ mod tests { ], }), &format!("0x{:064x}:0x{:04x}:0x{:04x}", 0, 0, 0), + block_timestamp, ) .await .unwrap(); @@ -147,6 +149,7 @@ mod tests { let model_name = "Record".to_string(); let key = vec![FieldElement::ONE]; let entity_id = format!("{:#x}", poseidon_hash_many(&key)); + let block_timestamp = 1710754478_u64; let keys_str = key.iter().map(|k| format!("{:#x}", k)).collect::>().join(","); let expected_value: async_graphql::Value = value!({ "entityUpdated": { @@ -204,6 +207,7 @@ mod tests { ], }), &format!("0x{:064x}:0x{:04x}:0x{:04x}", 0, 0, 0), + block_timestamp, ) .await .unwrap(); @@ -246,6 +250,7 @@ mod tests { let model_id = format!("{:#x}", get_selector_from_name(&model_name).unwrap()); let class_hash = FieldElement::TWO; let contract_address = FieldElement::THREE; + let block_timestamp: u64 = 1710754478_u64; let expected_value: async_graphql::Value = value!({ "modelRegistered": { "id": model_id, "name":model_name } }); @@ -263,7 +268,9 @@ mod tests { ty: Ty::Primitive(Primitive::U32(None)), }], }); - db.register_model(model, vec![], class_hash, contract_address, 0, 0).await.unwrap(); + db.register_model(model, vec![], class_hash, contract_address, 0, 0, block_timestamp) + .await + .unwrap(); // 3. fn publish() is called from state.set_entity() @@ -296,6 +303,7 @@ mod tests { let model_id = format!("{:#x}", get_selector_from_name(&model_name).unwrap()); let class_hash = FieldElement::TWO; let contract_address = FieldElement::THREE; + let block_timestamp: u64 = 1710754478_u64; let expected_value: async_graphql::Value = value!({ "modelRegistered": { "id": model_id, "name":model_name } }); @@ -313,7 +321,9 @@ mod tests { ty: Ty::Primitive(Primitive::U8(None)), }], }); - db.register_model(model, vec![], class_hash, contract_address, 0, 0).await.unwrap(); + db.register_model(model, vec![], class_hash, contract_address, 0, 0, block_timestamp) + .await + .unwrap(); // 3. fn publish() is called from state.set_entity() tx.send(()).await.unwrap(); @@ -343,7 +353,7 @@ mod tests { #[serial] async fn test_event_emitted(pool: SqlitePool) { let mut db = Sql::new(pool.clone(), FieldElement::ZERO).await.unwrap(); - + let block_timestamp: u64 = 1710754478_u64; let (tx, mut rx) = mpsc::channel(7); tokio::spawn(async move { tokio::time::sleep(Duration::from_secs(1)).await; @@ -362,6 +372,7 @@ mod tests { ], }, FieldElement::ZERO, + block_timestamp, ); tx.send(()).await.unwrap(); diff --git a/crates/torii/libp2p/Cargo.toml b/crates/torii/libp2p/Cargo.toml index 0503c861f1..e25d2a47bf 100644 --- a/crates/torii/libp2p/Cargo.toml +++ b/crates/torii/libp2p/Cargo.toml @@ -25,6 +25,7 @@ thiserror.workspace = true tracing-subscriber = { version = "0.3", features = [ "env-filter" ] } tracing.workspace = true indexmap = "2.2.5" +chrono.workspace = true [dev-dependencies] dojo-world = { path = "../../dojo-world", features = [ "metadata" ] } diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index 0ef61fc8ad..6a04b0c0b2 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -6,6 +6,7 @@ use std::str::FromStr; use std::time::Duration; use std::{fs, io}; +use chrono::Utc; use crypto_bigint::U256; use dojo_types::primitive::Primitive; use dojo_types::schema::{Member, Struct, Ty}; @@ -235,8 +236,14 @@ impl Relay { if entity.is_none() { // we can set the entity without checking identity - if let Err(e) = - self.db.set_entity(ty, &message_id.to_string()).await + if let Err(e) = self + .db + .set_entity( + ty, + &message_id.to_string(), + Utc::now().timestamp() as u64, + ) + .await { info!( target: "torii::relay::server", @@ -320,7 +327,11 @@ impl Relay { if let Err(e) = self .db // event id is message id - .set_entity(ty, &message_id.to_string()) + .set_entity( + ty, + &message_id.to_string(), + Utc::now().timestamp() as u64, + ) .await { info!( diff --git a/crates/torii/migrations/20230316154230_setup.sql b/crates/torii/migrations/20230316154230_setup.sql index 4f9edb7065..386966f739 100644 --- a/crates/torii/migrations/20230316154230_setup.sql +++ b/crates/torii/migrations/20230316154230_setup.sql @@ -16,6 +16,7 @@ CREATE TABLE worlds ( CREATE TABLE metadata ( id TEXT PRIMARY KEY NOT NULL, uri TEXT, + executed_at DATETIME NOT NULL, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); @@ -28,6 +29,7 @@ CREATE TABLE models ( class_hash TEXT NOT NULL, packed_size INTEGER NOT NULL, unpacked_size INTEGER NOT NULL, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); @@ -45,6 +47,8 @@ CREATE TABLE model_members( ) NOT NULL, enum_options TEXT NULL, -- TEMP: Remove once enum support is properly added key BOOLEAN NOT NULL, + -- TEMP: Remove CURRENT_TIMESTAMP + executed_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id, member_idx) FOREIGN KEY (model_id) REFERENCES models(id) ); @@ -67,6 +71,7 @@ CREATE TABLE entities ( keys TEXT, event_id TEXT NOT NULL, model_names TEXT, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); @@ -80,6 +85,7 @@ CREATE TABLE events ( keys TEXT NOT NULL, data TEXT NOT NULL, transaction_hash TEXT, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); diff --git a/crates/torii/migrations/20231030154053_remove_syscalls_add_txn.sql b/crates/torii/migrations/20231030154053_remove_syscalls_add_txn.sql index 026139fb02..482ba587c5 100644 --- a/crates/torii/migrations/20231030154053_remove_syscalls_add_txn.sql +++ b/crates/torii/migrations/20231030154053_remove_syscalls_add_txn.sql @@ -8,6 +8,7 @@ CREATE TABLE transactions ( max_fee TEXT NOT NULL, signature TEXT NOT NULL, nonce TEXT NOT NULL, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE (transaction_hash) ); diff --git a/crates/torii/migrations/20231127235011_entity_model.sql b/crates/torii/migrations/20231127235011_entity_model.sql index ed1838c9ac..0164aa7f21 100644 --- a/crates/torii/migrations/20231127235011_entity_model.sql +++ b/crates/torii/migrations/20231127235011_entity_model.sql @@ -5,13 +5,14 @@ CREATE TABLE entities_new ( id TEXT NOT NULL PRIMARY KEY, keys TEXT, event_id TEXT NOT NULL, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- Copy from old entities -INSERT INTO entities_new (id, keys, event_id, created_at, updated_at) -SELECT id, keys, event_id, created_at, updated_at +INSERT INTO entities_new (id, keys, event_id, executed_at, created_at, updated_at) +SELECT id, keys, event_id, executed_at, created_at, updated_at FROM entities; -- Disable foreign keys constraint so we can delete entities diff --git a/crates/torii/migrations/20240314182410_event_model.sql b/crates/torii/migrations/20240314182410_event_model.sql index 1cb4249e25..3e2ff3e7d0 100644 --- a/crates/torii/migrations/20240314182410_event_model.sql +++ b/crates/torii/migrations/20240314182410_event_model.sql @@ -3,6 +3,7 @@ CREATE TABLE event_messages ( keys TEXT, event_id TEXT NOT NULL, model_names TEXT, + executed_at DATETIME NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); From 4a77ef7f10b6f9c71c09afc2f5bfde69db20e699 Mon Sep 17 00:00:00 2001 From: glihm Date: Mon, 25 Mar 2024 13:32:30 -0600 Subject: [PATCH 4/6] [sozo] generate JSON manifest (#1694) * feat: add support for AbiFormat (path or embed) * fix: add example updated manifests * editor: add custom build commands * fix: remove print and fmt + clippy * add vscode settings to gitignore * fix: ensure pretty formatting of the json * chore: add all .vscode to gitignore * chore: remove vscode tasks * fix: enable PartialEq only for testing when required --- .gitignore | 1 + crates/dojo-lang/src/compiler.rs | 4 +- crates/dojo-world/src/manifest.rs | 124 ++++-- crates/sozo/ops/src/events.rs | 6 +- crates/sozo/ops/src/migration/mod.rs | 23 +- .../abis/base/contracts/actions.json | 2 +- .../deployments/KATANA/contracts/actions.json | 2 +- .../manifests/base/contracts/actions.toml | 2 +- .../manifests/base/models/moved.toml | 13 + .../manifests/deployments/KATANA.json | 357 ++++++++++++++++++ .../manifests/deployments/KATANA.toml | 22 +- 11 files changed, 508 insertions(+), 48 deletions(-) create mode 100644 examples/spawn-and-move/manifests/base/models/moved.toml create mode 100644 examples/spawn-and-move/manifests/deployments/KATANA.json diff --git a/.gitignore b/.gitignore index 144f0af73c..c6be219244 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ output.txt **/katana-logs crates/benches/bench_results.txt **/generated +.vscode diff --git a/crates/dojo-lang/src/compiler.rs b/crates/dojo-lang/src/compiler.rs index ae4466728e..6270a95755 100644 --- a/crates/dojo-lang/src/compiler.rs +++ b/crates/dojo-lang/src/compiler.rs @@ -17,7 +17,7 @@ use cairo_lang_utils::UpcastMut; use camino::Utf8PathBuf; use convert_case::{Case, Casing}; use dojo_world::manifest::{ - Class, ComputedValueEntrypoint, DojoContract, DojoModel, Manifest, ManifestMethods, + AbiFormat, Class, ComputedValueEntrypoint, DojoContract, DojoModel, Manifest, ManifestMethods, BASE_CONTRACT_NAME, WORLD_CONTRACT_NAME, }; use itertools::Itertools; @@ -451,7 +451,7 @@ where let relative_abi_path = relative_abis_dir.join(name.clone()).with_extension("json"); if abi.is_some() { - manifest.inner.set_abi(Some(relative_abi_path.clone())); + manifest.inner.set_abi(Some(AbiFormat::Path(relative_abi_path.clone()))); } let manifest_toml = toml::to_string_pretty(&manifest)?; diff --git a/crates/dojo-world/src/manifest.rs b/crates/dojo-world/src/manifest.rs index e4e0ce3d4d..b2a3916d5f 100644 --- a/crates/dojo-world/src/manifest.rs +++ b/crates/dojo-world/src/manifest.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use smol_str::SmolStr; use starknet::core::serde::unsigned_field_element::UfeHex; +use starknet::core::types::contract::AbiEntry; use starknet::core::types::{ BlockId, BlockTag, EmittedEvent, EventFilter, FieldElement, FunctionCall, StarknetError, }; @@ -75,13 +76,14 @@ impl From for Member { /// Represents a declaration of a model. #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] #[serde(tag = "kind")] pub struct DojoModel { pub members: Vec, #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, - pub abi: Option, + pub abi: Option, } /// System input ABI. @@ -110,23 +112,61 @@ pub struct ComputedValueEntrypoint { pub model: Option, } +/// Format of the ABI into the manifest. #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(untagged)] +pub enum AbiFormat { + /// Only a relative path to the ABI file is stored. + Path(Utf8PathBuf), + /// The full ABI is embedded. + Embed(Vec), +} + +#[cfg(test)] +impl PartialEq for AbiFormat { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (AbiFormat::Path(p1), AbiFormat::Path(p2)) => p1 == p2, + (AbiFormat::Embed(e1), AbiFormat::Embed(e2)) => { + // Currently, [`AbiEntry`] does not implement [`PartialEq`] so we cannot compare + // them directly. + let e1_json = serde_json::to_string(e1).expect("valid JSON from ABI"); + let e2_json = serde_json::to_string(e2).expect("valid JSON from ABI"); + e1_json == e2_json + } + _ => false, + } + } +} + +impl AbiFormat { + pub fn to_path(&self) -> Option<&Utf8PathBuf> { + match self { + AbiFormat::Path(p) => Some(p), + AbiFormat::Embed(_) => None, + } + } +} + +#[serde_as] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] #[serde(tag = "kind")] pub struct DojoContract { #[serde_as(as = "Option")] pub address: Option, #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, - pub abi: Option, + pub abi: Option, pub reads: Vec, pub writes: Vec, pub computed: Vec, } #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] - +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct OverlayDojoContract { pub name: SmolStr, pub reads: Option>, @@ -134,33 +174,38 @@ pub struct OverlayDojoContract { } #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct OverlayDojoModel {} #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct OverlayContract {} #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct OverlayClass {} #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] #[serde(tag = "kind")] pub struct Class { #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, - pub abi: Option, + pub abi: Option, } #[serde_as] -#[derive(Clone, Default, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] #[serde(tag = "kind")] pub struct Contract { #[serde_as(as = "UfeHex")] pub class_hash: FieldElement, - pub abi: Option, + pub abi: Option, #[serde_as(as = "Option")] pub address: Option, #[serde_as(as = "Option")] @@ -170,7 +215,8 @@ pub struct Contract { pub seed: Option, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct BaseManifest { pub world: Manifest, pub base: Manifest, @@ -202,7 +248,8 @@ impl From for DeploymentManifest { } } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct DeploymentManifest { pub world: Manifest, pub base: Manifest, @@ -210,12 +257,14 @@ pub struct DeploymentManifest { pub models: Vec>, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] pub struct OverlayManifest { pub contracts: Vec, } -#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug)] +#[cfg_attr(test, derive(PartialEq))] pub struct Manifest where T: ManifestMethods, @@ -236,8 +285,8 @@ where pub trait ManifestMethods { type OverlayType; - fn abi(&self) -> Option<&Utf8PathBuf>; - fn set_abi(&mut self, abi: Option); + fn abi(&self) -> Option<&AbiFormat>; + fn set_abi(&mut self, abi: Option); fn class_hash(&self) -> &FieldElement; fn set_class_hash(&mut self, class_hash: FieldElement); @@ -300,7 +349,7 @@ impl DeploymentManifest { self.world.inner.seed = previous.world.inner.seed; } - pub fn write_to_path(&self, path: &Utf8PathBuf) -> Result<()> { + pub fn write_to_path_toml(&self, path: &Utf8PathBuf) -> Result<()> { fs::create_dir_all(path.parent().unwrap())?; let deployed_manifest = toml::to_string_pretty(&self)?; @@ -309,6 +358,25 @@ impl DeploymentManifest { Ok(()) } + pub fn write_to_path_json(&self, path: &Utf8PathBuf, manifest_dir: &Utf8PathBuf) -> Result<()> { + fs::create_dir_all(path.parent().unwrap())?; + + // Embedding ABIs into the manifest. + let mut manifest_with_abis = self.clone(); + for contract in &mut manifest_with_abis.contracts { + if let Some(AbiFormat::Path(abi_path)) = &contract.inner.abi { + let mut abi_file = std::fs::File::open(manifest_dir.join(abi_path))?; + let abi_entries: Vec = serde_json::from_reader(&mut abi_file)?; + contract.inner.abi = Some(AbiFormat::Embed(abi_entries)); + } + } + + let deployed_manifest = serde_json::to_string_pretty(&manifest_with_abis)?; + fs::write(path, deployed_manifest)?; + + Ok(()) + } + /// Construct a manifest of a remote World. /// /// # Arguments @@ -628,11 +696,11 @@ where impl ManifestMethods for DojoContract { type OverlayType = OverlayDojoContract; - fn abi(&self) -> Option<&Utf8PathBuf> { + fn abi(&self) -> Option<&AbiFormat> { self.abi.as_ref() } - fn set_abi(&mut self, abi: Option) { + fn set_abi(&mut self, abi: Option) { self.abi = abi; } @@ -657,11 +725,11 @@ impl ManifestMethods for DojoContract { impl ManifestMethods for DojoModel { type OverlayType = OverlayDojoModel; - fn abi(&self) -> Option<&Utf8PathBuf> { + fn abi(&self) -> Option<&AbiFormat> { self.abi.as_ref() } - fn set_abi(&mut self, abi: Option) { + fn set_abi(&mut self, abi: Option) { self.abi = abi; } @@ -679,11 +747,11 @@ impl ManifestMethods for DojoModel { impl ManifestMethods for Contract { type OverlayType = OverlayContract; - fn abi(&self) -> Option<&Utf8PathBuf> { + fn abi(&self) -> Option<&AbiFormat> { self.abi.as_ref() } - fn set_abi(&mut self, abi: Option) { + fn set_abi(&mut self, abi: Option) { self.abi = abi; } @@ -701,11 +769,11 @@ impl ManifestMethods for Contract { impl ManifestMethods for Class { type OverlayType = OverlayClass; - fn abi(&self) -> Option<&Utf8PathBuf> { + fn abi(&self) -> Option<&AbiFormat> { self.abi.as_ref() } - fn set_abi(&mut self, abi: Option) { + fn set_abi(&mut self, abi: Option) { self.abi = abi; } diff --git a/crates/sozo/ops/src/events.rs b/crates/sozo/ops/src/events.rs index dab6401cc1..bca1ab3a67 100644 --- a/crates/sozo/ops/src/events.rs +++ b/crates/sozo/ops/src/events.rs @@ -6,7 +6,7 @@ use cainome::parser::tokens::{CompositeInner, CompositeInnerKind, CoreBasic, Tok use cainome::parser::AbiParser; use camino::Utf8PathBuf; use dojo_lang::compiler::{DEPLOYMENTS_DIR, MANIFESTS_DIR}; -use dojo_world::manifest::{DeploymentManifest, ManifestMethods}; +use dojo_world::manifest::{AbiFormat, DeploymentManifest, ManifestMethods}; use starknet::core::types::{BlockId, EventFilter, FieldElement}; use starknet::core::utils::{parse_cairo_short_string, starknet_keccak}; use starknet::providers::jsonrpc::HttpTransport; @@ -104,14 +104,14 @@ fn extract_events( let mut events_map = HashMap::new(); for contract in &manifest.contracts { - if let Some(abi_path) = contract.inner.abi() { + if let Some(AbiFormat::Path(abi_path)) = contract.inner.abi() { let full_abi_path = manifest_dir.join(abi_path); process_abi(&mut events_map, &full_abi_path)?; } } for model in &manifest.contracts { - if let Some(abi_path) = model.inner.abi() { + if let Some(AbiFormat::Path(abi_path)) = model.inner.abi() { let full_abi_path = manifest_dir.join(abi_path); process_abi(&mut events_map, &full_abi_path)?; } diff --git a/crates/sozo/ops/src/migration/mod.rs b/crates/sozo/ops/src/migration/mod.rs index 7c93ac4a6a..679855a2a4 100644 --- a/crates/sozo/ops/src/migration/mod.rs +++ b/crates/sozo/ops/src/migration/mod.rs @@ -7,7 +7,7 @@ use dojo_world::contracts::abi::world::ResourceMetadata; use dojo_world::contracts::cairo_utils; use dojo_world::contracts::world::WorldContract; use dojo_world::manifest::{ - AbstractManifestError, BaseManifest, DeploymentManifest, DojoContract, Manifest, + AbiFormat, AbstractManifestError, BaseManifest, DeploymentManifest, DojoContract, Manifest, ManifestMethods, OverlayManifest, }; use dojo_world::metadata::dojo_metadata_from_workspace; @@ -133,6 +133,10 @@ where Ok(()) } +fn build_deployed_path(manifest_dir: &Utf8PathBuf, chain_id: &str, extension: &str) -> Utf8PathBuf { + manifest_dir.join(MANIFESTS_DIR).join(DEPLOYMENTS_DIR).join(chain_id).with_extension(extension) +} + async fn update_manifests_and_abis( ws: &Workspace<'_>, local_manifest: BaseManifest, @@ -145,11 +149,8 @@ async fn update_manifests_and_abis( let ui = ws.config().ui(); ui.print("\nāœØ Updating manifests..."); - let deployed_path = manifest_dir - .join(MANIFESTS_DIR) - .join(DEPLOYMENTS_DIR) - .join(chain_id) - .with_extension("toml"); + let deployed_path = build_deployed_path(manifest_dir, chain_id, "toml"); + let deployed_path_json = build_deployed_path(manifest_dir, chain_id, "json"); let mut local_manifest: DeploymentManifest = local_manifest.into(); @@ -185,7 +186,8 @@ async fn update_manifests_and_abis( // local_manifest update_manifest_abis(&mut local_manifest, manifest_dir, chain_id).await; - local_manifest.write_to_path(&deployed_path)?; + local_manifest.write_to_path_toml(&deployed_path)?; + local_manifest.write_to_path_json(&deployed_path_json, manifest_dir)?; ui.print("\nāœØ Done."); Ok(()) @@ -204,8 +206,9 @@ async fn update_manifest_abis( where T: ManifestMethods, { - // unwraps in call to abi is safe because we always write abis for DojoContracts - let base_relative_path = manifest.inner.abi().unwrap(); + // unwraps in call to abi is safe because we always write abis for DojoContracts as relative + // path. + let base_relative_path = manifest.inner.abi().unwrap().to_path().unwrap(); let deployed_relative_path = Utf8PathBuf::new().join(ABIS_DIR).join(DEPLOYMENTS_DIR).join(chain_id).join( base_relative_path @@ -220,7 +223,7 @@ async fn update_manifest_abis( .await .expect("Failed to create folder"); fs::copy(full_base_path, full_deployed_path).await.expect("Failed to copy abi file"); - manifest.inner.set_abi(Some(deployed_relative_path)); + manifest.inner.set_abi(Some(AbiFormat::Path(deployed_relative_path))); } for contract in local_manifest.contracts.iter_mut() { diff --git a/examples/spawn-and-move/abis/base/contracts/actions.json b/examples/spawn-and-move/abis/base/contracts/actions.json index de4442aef8..f7c8509d5b 100644 --- a/examples/spawn-and-move/abis/base/contracts/actions.json +++ b/examples/spawn-and-move/abis/base/contracts/actions.json @@ -235,7 +235,7 @@ { "name": "player", "type": "core::starknet::contract_address::ContractAddress", - "kind": "data" + "kind": "key" }, { "name": "direction", diff --git a/examples/spawn-and-move/abis/deployments/KATANA/contracts/actions.json b/examples/spawn-and-move/abis/deployments/KATANA/contracts/actions.json index de4442aef8..f7c8509d5b 100644 --- a/examples/spawn-and-move/abis/deployments/KATANA/contracts/actions.json +++ b/examples/spawn-and-move/abis/deployments/KATANA/contracts/actions.json @@ -235,7 +235,7 @@ { "name": "player", "type": "core::starknet::contract_address::ContractAddress", - "kind": "data" + "kind": "key" }, { "name": "direction", diff --git a/examples/spawn-and-move/manifests/base/contracts/actions.toml b/examples/spawn-and-move/manifests/base/contracts/actions.toml index 41beef8c24..c5bed7ab76 100644 --- a/examples/spawn-and-move/manifests/base/contracts/actions.toml +++ b/examples/spawn-and-move/manifests/base/contracts/actions.toml @@ -1,5 +1,5 @@ kind = "DojoContract" -class_hash = "0xd43bce39922ec3857da231e3bb5c365c29f837c6dce322e4d61dfae83a4c18" +class_hash = "0x2a3b1c5473dfb9fd1be08b94fae201b30b4e63ed8caed996476cc4ad44cadb2" abi = "abis/base/contracts/actions.json" reads = [] writes = [] diff --git a/examples/spawn-and-move/manifests/base/models/moved.toml b/examples/spawn-and-move/manifests/base/models/moved.toml new file mode 100644 index 0000000000..71c08c95bb --- /dev/null +++ b/examples/spawn-and-move/manifests/base/models/moved.toml @@ -0,0 +1,13 @@ +kind = "DojoModel" +class_hash = "0x52659850f9939482810d9f6b468b91dc99e0b7fa42c2016cf12833ec06ce911" +name = "dojo_examples::actions::actions::moved" + +[[members]] +name = "player" +type = "ContractAddress" +key = true + +[[members]] +name = "direction" +type = "Direction" +key = false diff --git a/examples/spawn-and-move/manifests/deployments/KATANA.json b/examples/spawn-and-move/manifests/deployments/KATANA.json new file mode 100644 index 0000000000..844426adde --- /dev/null +++ b/examples/spawn-and-move/manifests/deployments/KATANA.json @@ -0,0 +1,357 @@ +{ + "world": { + "kind": "Contract", + "class_hash": "0x799bc4e9da10bfb3dd88e6f223c9cfbf7745435cd14f5d69675ea448e578cd", + "abi": null, + "address": "0x1385f25d20a724edc9c7b3bd9636c59af64cbaf9fcd12f33b3af96b2452f295", + "transaction_hash": "0x6afefdcc49b3563a4f3657900ba71e9f9356861b15b942a73f2018f046a1048", + "block_number": 3, + "seed": "dojo_examples", + "name": "dojo::world::world" + }, + "base": { + "kind": "Class", + "class_hash": "0x679177a2cb757694ac4f326d01052ff0963eac0bc2a17116a2b87badcdf6f76", + "abi": null, + "name": "dojo::base::base" + }, + "contracts": [ + { + "kind": "DojoContract", + "address": "0x3539c9b89b08095ba914653fb0f20e55d4b172a415beade611bc260b346d0f7", + "class_hash": "0x2a3b1c5473dfb9fd1be08b94fae201b30b4e63ed8caed996476cc4ad44cadb2", + "abi": [ + { + "type": "impl", + "name": "DojoResourceProviderImpl", + "interface_name": "dojo::world::IDojoResourceProvider" + }, + { + "type": "interface", + "name": "dojo::world::IDojoResourceProvider", + "items": [ + { + "type": "function", + "name": "dojo_resource", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "WorldProviderImpl", + "interface_name": "dojo::world::IWorldProvider" + }, + { + "type": "struct", + "name": "dojo::world::IWorldDispatcher", + "members": [ + { + "name": "contract_address", + "type": "core::starknet::contract_address::ContractAddress" + } + ] + }, + { + "type": "interface", + "name": "dojo::world::IWorldProvider", + "items": [ + { + "type": "function", + "name": "world", + "inputs": [], + "outputs": [ + { + "type": "dojo::world::IWorldDispatcher" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "ActionsComputedImpl", + "interface_name": "dojo_examples::actions::IActionsComputed" + }, + { + "type": "struct", + "name": "dojo_examples::models::Vec2", + "members": [ + { + "name": "x", + "type": "core::integer::u32" + }, + { + "name": "y", + "type": "core::integer::u32" + } + ] + }, + { + "type": "struct", + "name": "dojo_examples::models::Position", + "members": [ + { + "name": "player", + "type": "core::starknet::contract_address::ContractAddress" + }, + { + "name": "vec", + "type": "dojo_examples::models::Vec2" + } + ] + }, + { + "type": "interface", + "name": "dojo_examples::actions::IActionsComputed", + "items": [ + { + "type": "function", + "name": "tile_terrain", + "inputs": [ + { + "name": "vec", + "type": "dojo_examples::models::Vec2" + } + ], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" + }, + { + "type": "function", + "name": "quadrant", + "inputs": [ + { + "name": "pos", + "type": "dojo_examples::models::Position" + } + ], + "outputs": [ + { + "type": "core::integer::u8" + } + ], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "ActionsImpl", + "interface_name": "dojo_examples::actions::IActions" + }, + { + "type": "enum", + "name": "dojo_examples::models::Direction", + "variants": [ + { + "name": "None", + "type": "()" + }, + { + "name": "Left", + "type": "()" + }, + { + "name": "Right", + "type": "()" + }, + { + "name": "Up", + "type": "()" + }, + { + "name": "Down", + "type": "()" + } + ] + }, + { + "type": "interface", + "name": "dojo_examples::actions::IActions", + "items": [ + { + "type": "function", + "name": "spawn", + "inputs": [], + "outputs": [], + "state_mutability": "view" + }, + { + "type": "function", + "name": "move", + "inputs": [ + { + "name": "direction", + "type": "dojo_examples::models::Direction" + } + ], + "outputs": [], + "state_mutability": "view" + } + ] + }, + { + "type": "impl", + "name": "UpgradableImpl", + "interface_name": "dojo::components::upgradeable::IUpgradeable" + }, + { + "type": "interface", + "name": "dojo::components::upgradeable::IUpgradeable", + "items": [ + { + "type": "function", + "name": "upgrade", + "inputs": [ + { + "name": "new_class_hash", + "type": "core::starknet::class_hash::ClassHash" + } + ], + "outputs": [], + "state_mutability": "external" + } + ] + }, + { + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "struct", + "members": [ + { + "name": "class_hash", + "type": "core::starknet::class_hash::ClassHash", + "kind": "data" + } + ] + }, + { + "type": "event", + "name": "dojo::components::upgradeable::upgradeable::Event", + "kind": "enum", + "variants": [ + { + "name": "Upgraded", + "type": "dojo::components::upgradeable::upgradeable::Upgraded", + "kind": "nested" + } + ] + }, + { + "type": "event", + "name": "dojo_examples::actions::actions::Moved", + "kind": "struct", + "members": [ + { + "name": "player", + "type": "core::starknet::contract_address::ContractAddress", + "kind": "key" + }, + { + "name": "direction", + "type": "dojo_examples::models::Direction", + "kind": "data" + } + ] + }, + { + "type": "event", + "name": "dojo_examples::actions::actions::Event", + "kind": "enum", + "variants": [ + { + "name": "UpgradeableEvent", + "type": "dojo::components::upgradeable::upgradeable::Event", + "kind": "nested" + }, + { + "name": "Moved", + "type": "dojo_examples::actions::actions::Moved", + "kind": "nested" + } + ] + } + ], + "reads": [ + "Moves", + "Position" + ], + "writes": [], + "computed": [], + "name": "dojo_examples::actions::actions" + } + ], + "models": [ + { + "kind": "DojoModel", + "members": [ + { + "name": "player", + "type": "ContractAddress", + "key": true + }, + { + "name": "direction", + "type": "Direction", + "key": false + } + ], + "class_hash": "0x52659850f9939482810d9f6b468b91dc99e0b7fa42c2016cf12833ec06ce911", + "abi": null, + "name": "dojo_examples::actions::actions::moved" + }, + { + "kind": "DojoModel", + "members": [ + { + "name": "player", + "type": "ContractAddress", + "key": true + }, + { + "name": "remaining", + "type": "u8", + "key": false + }, + { + "name": "last_direction", + "type": "Direction", + "key": false + } + ], + "class_hash": "0x511fbd833938f5c4b743eea1e67605a125d7ff60e8a09e8dc227ad2fb59ca54", + "abi": null, + "name": "dojo_examples::models::moves" + }, + { + "kind": "DojoModel", + "members": [ + { + "name": "player", + "type": "ContractAddress", + "key": true + }, + { + "name": "vec", + "type": "Vec2", + "key": false + } + ], + "class_hash": "0xb33ae053213ccb2a57967ffc4411901f3efab24781ca867adcd0b90f2fece5", + "abi": null, + "name": "dojo_examples::models::position" + } + ] +} \ No newline at end of file diff --git a/examples/spawn-and-move/manifests/deployments/KATANA.toml b/examples/spawn-and-move/manifests/deployments/KATANA.toml index 9a186f0e41..72bc65458c 100644 --- a/examples/spawn-and-move/manifests/deployments/KATANA.toml +++ b/examples/spawn-and-move/manifests/deployments/KATANA.toml @@ -15,13 +15,31 @@ name = "dojo::base::base" [[contracts]] kind = "DojoContract" address = "0x3539c9b89b08095ba914653fb0f20e55d4b172a415beade611bc260b346d0f7" -class_hash = "0xd43bce39922ec3857da231e3bb5c365c29f837c6dce322e4d61dfae83a4c18" +class_hash = "0x2a3b1c5473dfb9fd1be08b94fae201b30b4e63ed8caed996476cc4ad44cadb2" abi = "abis/deployments/KATANA/contracts/actions.json" -reads = [] +reads = [ + "Moves", + "Position", +] writes = [] computed = [] name = "dojo_examples::actions::actions" +[[models]] +kind = "DojoModel" +class_hash = "0x52659850f9939482810d9f6b468b91dc99e0b7fa42c2016cf12833ec06ce911" +name = "dojo_examples::actions::actions::moved" + +[[models.members]] +name = "player" +type = "ContractAddress" +key = true + +[[models.members]] +name = "direction" +type = "Direction" +key = false + [[models]] kind = "DojoModel" class_hash = "0x511fbd833938f5c4b743eea1e67605a125d7ff60e8a09e8dc227ad2fb59ca54" From 4af8b033a796db9554506dc9e0e6d97d113aadcc Mon Sep 17 00:00:00 2001 From: Tarrence van As Date: Mon, 25 Mar 2024 16:01:13 -0400 Subject: [PATCH 5/6] Prepare release: v0.6.0-alpha.8 (#1699) --- Cargo.lock | 86 ++++++++++---------- Cargo.toml | 2 +- crates/katana/runner/runner-macro/Cargo.toml | 2 +- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0da22cf1de..304e743f38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -957,7 +957,7 @@ dependencies = [ [[package]] name = "benches" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "clap", @@ -2497,7 +2497,7 @@ dependencies = [ [[package]] name = "common" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "reqwest", @@ -3226,7 +3226,7 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dojo-bindgen" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "async-trait", "cainome 0.1.5", @@ -3241,15 +3241,15 @@ dependencies = [ [[package]] name = "dojo-core" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" [[package]] name = "dojo-examples-spawn-and-move" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" [[package]] name = "dojo-lang" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -3299,7 +3299,7 @@ dependencies = [ [[package]] name = "dojo-language-server" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -3321,7 +3321,7 @@ dependencies = [ [[package]] name = "dojo-test-utils" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_fs", @@ -3354,7 +3354,7 @@ dependencies = [ [[package]] name = "dojo-types" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "crypto-bigint", "hex", @@ -3369,7 +3369,7 @@ dependencies = [ [[package]] name = "dojo-world" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_fs", @@ -3404,7 +3404,7 @@ dependencies = [ [[package]] name = "dojo-world-abigen" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "cairo-lang-starknet", "camino", @@ -6564,7 +6564,7 @@ dependencies = [ [[package]] name = "katana" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -6576,7 +6576,7 @@ dependencies = [ "katana-primitives", "katana-rpc", "katana-rpc-api", - "metrics 0.6.0-alpha.7", + "metrics 0.6.0-alpha.8", "metrics-process", "serde_json", "shellexpand", @@ -6589,7 +6589,7 @@ dependencies = [ [[package]] name = "katana-codecs" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "bytes", "katana-primitives", @@ -6597,7 +6597,7 @@ dependencies = [ [[package]] name = "katana-codecs-derive" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "proc-macro2", "quote", @@ -6607,7 +6607,7 @@ dependencies = [ [[package]] name = "katana-core" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -6643,7 +6643,7 @@ dependencies = [ [[package]] name = "katana-db" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "blockifier", @@ -6665,7 +6665,7 @@ dependencies = [ [[package]] name = "katana-executor" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "blockifier", @@ -6683,7 +6683,7 @@ dependencies = [ [[package]] name = "katana-primitives" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "base64 0.21.7", @@ -6709,7 +6709,7 @@ dependencies = [ [[package]] name = "katana-provider" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "auto_impl", @@ -6734,7 +6734,7 @@ dependencies = [ [[package]] name = "katana-rpc" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_matches", @@ -6768,7 +6768,7 @@ dependencies = [ [[package]] name = "katana-rpc-api" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "jsonrpsee 0.16.3", "katana-core", @@ -6779,7 +6779,7 @@ dependencies = [ [[package]] name = "katana-rpc-types" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "derive_more", @@ -6798,7 +6798,7 @@ dependencies = [ [[package]] name = "katana-rpc-types-builder" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "katana-executor", @@ -6810,7 +6810,7 @@ dependencies = [ [[package]] name = "katana-runner" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "chrono", @@ -6829,7 +6829,7 @@ dependencies = [ [[package]] name = "katana-tasks" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "futures", "rayon", @@ -7702,7 +7702,7 @@ dependencies = [ [[package]] name = "metrics" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "hyper", @@ -10024,7 +10024,7 @@ checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" [[package]] name = "runner-macro" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "quote", "syn 2.0.48", @@ -10251,7 +10251,7 @@ dependencies = [ [[package]] name = "saya" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "clap", @@ -10270,7 +10270,7 @@ dependencies = [ [[package]] name = "saya-core" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", @@ -11073,7 +11073,7 @@ dependencies = [ [[package]] name = "sozo" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_fs", @@ -11123,7 +11123,7 @@ dependencies = [ [[package]] name = "sozo-ops" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_fs", @@ -11172,7 +11172,7 @@ dependencies = [ [[package]] name = "sozo-signers" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "starknet 0.9.0", @@ -12483,7 +12483,7 @@ dependencies = [ [[package]] name = "torii" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", @@ -12503,7 +12503,7 @@ dependencies = [ "hyper-reverse-proxy", "indexmap 1.9.3", "lazy_static", - "metrics 0.6.0-alpha.7", + "metrics 0.6.0-alpha.8", "metrics-process", "scarb", "serde", @@ -12529,7 +12529,7 @@ dependencies = [ [[package]] name = "torii-client" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "async-trait", "camino", @@ -12557,7 +12557,7 @@ dependencies = [ [[package]] name = "torii-core" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", @@ -12594,7 +12594,7 @@ dependencies = [ [[package]] name = "torii-graphql" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-graphql", @@ -12635,7 +12635,7 @@ dependencies = [ [[package]] name = "torii-grpc" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "bytes", "crypto-bigint", @@ -12674,7 +12674,7 @@ dependencies = [ [[package]] name = "torii-relay" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", @@ -12709,7 +12709,7 @@ dependencies = [ [[package]] name = "torii-server" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", @@ -12728,7 +12728,7 @@ dependencies = [ "hyper-reverse-proxy", "indexmap 1.9.3", "lazy_static", - "metrics 0.6.0-alpha.7", + "metrics 0.6.0-alpha.8", "metrics-process", "scarb", "serde", @@ -13026,7 +13026,7 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "types-test" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" [[package]] name = "ucd-trie" diff --git a/Cargo.toml b/Cargo.toml index bc5f44e2e9..4a509a3e25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ edition = "2021" license = "Apache-2.0" license-file = "LICENSE" repository = "https://github.com/dojoengine/dojo/" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" [profile.performance] codegen-units = 1 diff --git a/crates/katana/runner/runner-macro/Cargo.toml b/crates/katana/runner/runner-macro/Cargo.toml index a2617ff5c9..2dd6cd44f7 100644 --- a/crates/katana/runner/runner-macro/Cargo.toml +++ b/crates/katana/runner/runner-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "runner-macro" -version = "0.6.0-alpha.7" +version = "0.6.0-alpha.8" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 5340720d76b6643d5443475d93ae9f8e6b16d032 Mon Sep 17 00:00:00 2001 From: Ammar Arif Date: Tue, 26 Mar 2024 23:44:20 +0800 Subject: [PATCH 6/6] `katana-executor` rewrite + `starknet_in_rust` intergration + `saya` namespace (#1697) * refactor(katana): change stored compiled class (#1559) Both `blockifier` and `starknet_in_rust` use their own proprietary contract class types. So need to have a type where the types from those two crates can be derived from. * refactor(katana-primitives): move class related types to a separate module (#1560) * Katana executor traits (#1561) * feat(katana-executor): add `blockifier` executor implementations (#1562) implement the executor traits introduced in #1561 based on `blockifier` * Refactor Katana to using the new executor traits (#1563) integrate the new executor traits introduced in #1561 to katana * feat(katana-executor): add starknet_in_rust executor (#1564) * doc(katana-executor): add README * test(katana-executor): add test for transaction simulation (#1593) * test(katana-executor): refactor simulate tests (#1606) refactor tests * refactor(katana): decouple `katana-primitives` from any executor impls (#1637) * test(katana-executor): improve tests and add test for state (#1649) - add tests for each executor's CachedState - improve test in executor.rs - fix sir not enough gas error - fix test in simulate.rs * feat(saya): load data from Katana to run `SNOS` (#1535) * chore: bump dependencies * fix: update cairo-lang * fix: add missing run_profiler * fix: fmt * update cairo-vm rev * wip * wip * fmt * fix: ensure semantics analyzer plugin is registered * chore(katana): make ethers non optional since U256 is used outside messaging * fix: run CAIRO_FIX_TESTS * fix(dojo-core): remove compiler warnings * git: add sozo generated bindings to gitignore * fix: fix class hash * fix: class hash generated code * fix(dojo-core): fix tests and compilation warnings * chore: integrate snos on cairo2.5 * chore: update Cargo.lock * wip: work on integration of katana types * wip: fetch strategy * fix * feat: add parsing of state diff for genesis block * wip * wip * fix: rework provider for saya and RPC implem * wip * wip: snos types * wip txs * wip: fix snos parsing need to complete inputs * chore: switch back to git snos * chore: bump blockifier to use Serde on TransactionExecutionInfo * feat: add saya RPC namespace * feat: add transaction execution info to in memory db * fix: remove unused code covered by other test * fix: add logic for small requests to get transactions executions info * fix: fetch transactions executions info instead of running blockifier * fix: fmt and clippy * docs: fix unused type * fix: add tests for new transactions execution retrieval * fix: add correct test to check no pending support * fix: restore unchanged file * fix: rename new provider trait to TransactionTraceProvider * refactor(katana): change stored compiled class (#1559) Both `blockifier` and `starknet_in_rust` use their own proprietary contract class types. So need to have a type where the types from those two crates can be derived from. * refactor(katana-primitives): move class related types to a separate module (#1560) * Katana executor traits (#1561) * feat(katana-executor): add `blockifier` executor implementations (#1562) implement the executor traits introduced in #1561 based on `blockifier` * Refactor Katana to using the new executor traits (#1563) integrate the new executor traits introduced in #1561 to katana * feat(katana-executor): add starknet_in_rust executor (#1564) * doc(katana-executor): add README * test(katana-executor): add test for transaction simulation (#1593) * test(katana-executor): refactor simulate tests (#1606) refactor tests * adjust new types for Katana blockchain and SNOS * fix: clippy * refactor(katana): change stored compiled class (#1559) Both `blockifier` and `starknet_in_rust` use their own proprietary contract class types. So need to have a type where the types from those two crates can be derived from. * refactor(katana-primitives): move class related types to a separate module (#1560) * Katana executor traits (#1561) * feat(katana-executor): add `blockifier` executor implementations (#1562) implement the executor traits introduced in #1561 based on `blockifier` * Refactor Katana to using the new executor traits (#1563) integrate the new executor traits introduced in #1561 to katana * feat(katana-executor): add starknet_in_rust executor (#1564) * doc(katana-executor): add README * test(katana-executor): add test for transaction simulation (#1593) * test(katana-executor): refactor simulate tests (#1606) refactor tests * feat: add new primitive for trace and blockifier conversions * feat: add TransactionExecutionInfo convert from blockifier * feat: add executor trait method to retrieve the execution info * fix: ensure tx execution info is passed in block producer * chore: restore dependency on blockifier as we use TxExecInfo primitive * refactor(katana): decouple `katana-primitives` from any executor impls (#1637) * fix: clippy / fmt * merge * fix: clippy --------- Co-authored-by: Kariy Co-authored-by: Ammar Arif * feat(katana-primitives): add fee info type * Refactor executor output * fix(katana): add missing contract address in `CallInfo` * Remove `native` feature for now * Limit nextest build jobs * refactor(katana-executor): add logs for transaction events and resources * fix(katana-executor): return reverted tx as error in estimate fee --------- Co-authored-by: glihm --- .devcontainer/Dockerfile | 15 +- .github/workflows/ci.yml | 22 +- Cargo.lock | 953 +- Cargo.toml | 15 +- bin/katana/Cargo.toml | 8 +- bin/katana/src/args.rs | 2 +- bin/katana/src/main.rs | 42 +- bin/saya/src/args/mod.rs | 2 +- bin/saya/src/main.rs | 2 +- crates/dojo-test-utils/Cargo.toml | 1 + crates/dojo-test-utils/src/sequencer.rs | 37 +- crates/katana/core/Cargo.toml | 9 +- crates/katana/core/src/backend/contract.rs | 4 +- crates/katana/core/src/backend/mod.rs | 100 +- crates/katana/core/src/backend/storage.rs | 14 +- crates/katana/core/src/sequencer.rs | 199 +- crates/katana/core/src/sequencer_error.rs | 6 - .../katana/core/src/service/block_producer.rs | 505 +- .../core/src/service/messaging/service.rs | 15 +- crates/katana/core/src/service/mod.rs | 19 +- crates/katana/core/tests/sequencer.rs | 6 +- crates/katana/executor/.env.cairo-native | 3 + crates/katana/executor/Cargo.toml | 37 +- crates/katana/executor/README.md | 41 + .../katana/executor/src/abstraction/error.rs | 62 + .../executor/src/abstraction/executor.rs | 73 + crates/katana/executor/src/abstraction/mod.rs | 186 + crates/katana/executor/src/blockifier/mod.rs | 232 - .../katana/executor/src/blockifier/outcome.rs | 82 - .../katana/executor/src/blockifier/state.rs | 245 - .../executor/src/blockifier/transactions.rs | 241 - .../katana/executor/src/blockifier/utils.rs | 562 - .../src/implementation/blockifier/error.rs | 103 + .../src/implementation/blockifier/mod.rs | 261 + .../src/implementation/blockifier/output.rs | 153 + .../src/implementation/blockifier/state.rs | 548 + .../src/implementation/blockifier/utils.rs | 615 + .../katana/executor/src/implementation/mod.rs | 7 + .../executor/src/implementation/noop.rs | 166 + .../executor/src/implementation/sir/error.rs | 43 + .../executor/src/implementation/sir/mod.rs | 269 + .../executor/src/implementation/sir/output.rs | 153 + .../executor/src/implementation/sir/state.rs | 583 + .../executor/src/implementation/sir/utils.rs | 731 ++ crates/katana/executor/src/lib.rs | 6 +- crates/katana/executor/src/utils.rs | 41 + crates/katana/executor/tests/executor.rs | 329 + .../executor/tests/fixtures/contract.json | 1 + .../tests/fixtures/legacy_contract.json} | 0 crates/katana/executor/tests/fixtures/mod.rs | 294 + .../executor/tests/fixtures/transaction.rs | 111 + crates/katana/executor/tests/simulate.rs | 115 + crates/katana/primitives/Cargo.toml | 8 +- .../contracts/compiled/account.json | 10273 +++++++++------- crates/katana/primitives/src/block.rs | 21 +- crates/katana/primitives/src/class.rs | 38 + crates/katana/primitives/src/contract.rs | 19 +- .../primitives/src/conversion/blockifier.rs | 48 - .../katana/primitives/src/conversion/mod.rs | 2 - .../katana/primitives/src/conversion/rpc.rs | 391 +- crates/katana/primitives/src/event.rs | 10 + crates/katana/primitives/src/fee.rs | 14 + .../primitives/src/genesis/allocation.rs | 3 +- .../katana/primitives/src/genesis/constant.rs | 17 +- crates/katana/primitives/src/genesis/json.rs | 24 +- crates/katana/primitives/src/genesis/mod.rs | 8 +- crates/katana/primitives/src/lib.rs | 4 + crates/katana/primitives/src/message.rs | 11 + crates/katana/primitives/src/receipt.rs | 13 +- crates/katana/primitives/src/state.rs | 8 +- crates/katana/primitives/src/trace.rs | 88 + crates/katana/primitives/src/transaction.rs | 14 +- crates/katana/primitives/src/utils/class.rs | 38 +- crates/katana/rpc/rpc-api/src/lib.rs | 2 + crates/katana/rpc/rpc-api/src/saya.rs | 20 + crates/katana/rpc/rpc-types/Cargo.toml | 1 + crates/katana/rpc/rpc-types/src/account.rs | 3 +- crates/katana/rpc/rpc-types/src/error/mod.rs | 1 + crates/katana/rpc/rpc-types/src/error/saya.rs | 53 + .../rpc/rpc-types/src/error/starknet.rs | 16 +- .../katana/rpc/rpc-types/src/error/torii.rs | 8 +- crates/katana/rpc/rpc-types/src/lib.rs | 1 + crates/katana/rpc/rpc-types/src/trace.rs | 74 + .../katana/rpc/rpc-types/src/transaction.rs | 31 +- crates/katana/rpc/rpc/src/dev.rs | 11 +- crates/katana/rpc/rpc/src/katana.rs | 11 +- crates/katana/rpc/rpc/src/lib.rs | 12 +- crates/katana/rpc/rpc/src/saya.rs | 76 + crates/katana/rpc/rpc/src/starknet.rs | 362 +- crates/katana/rpc/rpc/src/torii.rs | 73 +- crates/katana/rpc/rpc/tests/common/mod.rs | 30 + crates/katana/rpc/rpc/tests/saya.rs | 186 + crates/katana/rpc/rpc/tests/starknet.rs | 5 +- crates/katana/rpc/rpc/tests/torii.rs | 20 +- crates/katana/storage/db/Cargo.toml | 1 - crates/katana/storage/db/benches/codec.rs | 17 +- crates/katana/storage/db/src/codecs/mod.rs | 3 +- .../katana/storage/db/src/codecs/postcard.rs | 5 +- crates/katana/storage/db/src/models/class.rs | 522 +- .../katana/storage/db/src/models/contract.rs | 3 +- crates/katana/storage/db/src/tables.rs | 16 +- crates/katana/storage/provider/Cargo.toml | 4 +- crates/katana/storage/provider/src/error.rs | 7 +- crates/katana/storage/provider/src/lib.rs | 32 +- .../storage/provider/src/providers/db/mod.rs | 27 +- .../provider/src/providers/db/state.rs | 22 +- .../provider/src/providers/fork/backend.rs | 10 +- .../provider/src/providers/fork/mod.rs | 53 +- .../provider/src/providers/fork/state.rs | 10 +- .../provider/src/providers/in_memory/cache.rs | 11 +- .../provider/src/providers/in_memory/mod.rs | 54 +- .../provider/src/providers/in_memory/state.rs | 8 +- .../storage/provider/src/traits/block.rs | 2 + .../storage/provider/src/traits/contract.rs | 10 +- .../storage/provider/src/traits/state.rs | 3 +- .../provider/src/traits/transaction.rs | 13 + crates/katana/storage/provider/tests/block.rs | 1 + crates/katana/storage/provider/tests/class.rs | 14 +- .../katana/storage/provider/tests/contract.rs | 3 +- .../katana/storage/provider/tests/fixtures.rs | 15 +- crates/katana/tasks/src/lib.rs | 4 +- crates/saya/core/Cargo.toml | 5 +- crates/saya/core/src/blockchain/mod.rs | 152 + crates/saya/core/src/data_availability/mod.rs | 1 - crates/saya/core/src/error.rs | 10 + crates/saya/core/src/lib.rs | 81 +- crates/saya/core/src/starknet_os/felt.rs | 25 + crates/saya/core/src/starknet_os/input.rs | 23 + crates/saya/core/src/starknet_os/mod.rs | 8 + .../saya/core/src/starknet_os/transaction.rs | 120 + crates/saya/provider/Cargo.toml | 34 + crates/saya/provider/src/error.rs | 16 + crates/saya/provider/src/lib.rs | 13 + crates/saya/provider/src/provider.rs | 44 + crates/saya/provider/src/rpc/mod.rs | 179 + .../src/rpc/state.rs} | 53 +- crates/saya/provider/src/rpc/state_diff.rs | 12 + crates/saya/provider/src/rpc/transaction.rs | 164 + scripts/clippy.sh | 8 +- scripts/docs.sh | 3 +- 140 files changed, 14176 insertions(+), 7962 deletions(-) create mode 100644 crates/katana/executor/.env.cairo-native create mode 100644 crates/katana/executor/README.md create mode 100644 crates/katana/executor/src/abstraction/error.rs create mode 100644 crates/katana/executor/src/abstraction/executor.rs create mode 100644 crates/katana/executor/src/abstraction/mod.rs delete mode 100644 crates/katana/executor/src/blockifier/mod.rs delete mode 100644 crates/katana/executor/src/blockifier/outcome.rs delete mode 100644 crates/katana/executor/src/blockifier/state.rs delete mode 100644 crates/katana/executor/src/blockifier/transactions.rs delete mode 100644 crates/katana/executor/src/blockifier/utils.rs create mode 100644 crates/katana/executor/src/implementation/blockifier/error.rs create mode 100644 crates/katana/executor/src/implementation/blockifier/mod.rs create mode 100644 crates/katana/executor/src/implementation/blockifier/output.rs create mode 100644 crates/katana/executor/src/implementation/blockifier/state.rs create mode 100644 crates/katana/executor/src/implementation/blockifier/utils.rs create mode 100644 crates/katana/executor/src/implementation/mod.rs create mode 100644 crates/katana/executor/src/implementation/noop.rs create mode 100644 crates/katana/executor/src/implementation/sir/error.rs create mode 100644 crates/katana/executor/src/implementation/sir/mod.rs create mode 100644 crates/katana/executor/src/implementation/sir/output.rs create mode 100644 crates/katana/executor/src/implementation/sir/state.rs create mode 100644 crates/katana/executor/src/implementation/sir/utils.rs create mode 100644 crates/katana/executor/src/utils.rs create mode 100644 crates/katana/executor/tests/executor.rs create mode 120000 crates/katana/executor/tests/fixtures/contract.json rename crates/katana/{primitives/contracts/compiled/test_contract.json => executor/tests/fixtures/legacy_contract.json} (100%) create mode 100644 crates/katana/executor/tests/fixtures/mod.rs create mode 100644 crates/katana/executor/tests/fixtures/transaction.rs create mode 100644 crates/katana/executor/tests/simulate.rs create mode 100644 crates/katana/primitives/src/class.rs delete mode 100644 crates/katana/primitives/src/conversion/blockifier.rs create mode 100644 crates/katana/primitives/src/fee.rs create mode 100644 crates/katana/primitives/src/message.rs create mode 100644 crates/katana/primitives/src/trace.rs create mode 100644 crates/katana/rpc/rpc-api/src/saya.rs create mode 100644 crates/katana/rpc/rpc-types/src/error/saya.rs create mode 100644 crates/katana/rpc/rpc-types/src/trace.rs create mode 100644 crates/katana/rpc/rpc/src/saya.rs create mode 100644 crates/katana/rpc/rpc/tests/saya.rs create mode 100644 crates/saya/core/src/blockchain/mod.rs create mode 100644 crates/saya/core/src/starknet_os/felt.rs create mode 100644 crates/saya/core/src/starknet_os/input.rs create mode 100644 crates/saya/core/src/starknet_os/mod.rs create mode 100644 crates/saya/core/src/starknet_os/transaction.rs create mode 100644 crates/saya/provider/Cargo.toml create mode 100644 crates/saya/provider/src/error.rs create mode 100644 crates/saya/provider/src/lib.rs create mode 100644 crates/saya/provider/src/provider.rs create mode 100644 crates/saya/provider/src/rpc/mod.rs rename crates/saya/{core/src/data_availability/state_diff.rs => provider/src/rpc/state.rs} (89%) create mode 100644 crates/saya/provider/src/rpc/state_diff.rs create mode 100644 crates/saya/provider/src/rpc/transaction.rs diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 0895fc1ad4..441c7e91b5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -4,12 +4,23 @@ ARG VARIANT FROM mcr.microsoft.com/vscode/devcontainers/rust:${VARIANT} +ARG VARIANT # Install additional packages RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ - && apt-get -y install --no-install-recommends protobuf-compiler libprotobuf-dev libclang-dev + && apt-get -y install --no-install-recommends protobuf-compiler libprotobuf-dev libclang-dev libzstd-dev + +RUN apt install -y gh libgmp3-dev software-properties-common + +# Install Cairo Native dependencies +RUN curl -s https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc > /dev/null +RUN echo "deb http://apt.llvm.org/${VARIANT}/ llvm-toolchain-${VARIANT}-17 main" | tee /etc/apt/sources.list.d/llvm.list && apt-get update +RUN apt-get -y install -t llvm-toolchain-${VARIANT}-17 llvm-17 llvm-17-dev llvm-17-runtime clang-17 clang-tools-17 lld-17 libpolly-17-dev libmlir-17-dev mlir-17-tools -RUN apt install -y gh libgmp3-dev +# To build Katana with 'native' feature, we need to set the following environment variables +ENV MLIR_SYS_170_PREFIX=/usr/lib/llvm-17 +ENV LLVM_SYS_170_PREFIX=/usr/lib/llvm-17 +ENV TABLEGEN_170_PREFIX=/usr/lib/llvm-17 # To allow independent workflow of the container, the rust-toolchain is explicitely given. RUN echo "1.74.0" > rust_toolchain_version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cab4a26e16..d9414adf04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,11 +14,15 @@ jobs: test: runs-on: ubuntu-latest-16-cores container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 - - run: cargo build -r --bin katana && cargo llvm-cov nextest --all-features --lcov --output-path lcov.info + - run: | + cargo llvm-cov nextest --no-report --all-features --workspace --exclude katana --build-jobs 10 + cargo llvm-cov nextest --no-report -p katana + cargo llvm-cov nextest --no-report -p katana --no-default-features --features sir + cargo llvm-cov report --lcov --output-path lcov.info - uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -27,7 +31,7 @@ jobs: ensure-wasm: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -62,7 +66,7 @@ jobs: dojo-core-test: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -71,7 +75,7 @@ jobs: dojo-spawn-and-move-example-test: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -80,7 +84,7 @@ jobs: dojo-world-bindings-check: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -89,7 +93,7 @@ jobs: clippy: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -98,7 +102,7 @@ jobs: fmt: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 @@ -107,7 +111,7 @@ jobs: docs: runs-on: ubuntu-latest container: - image: ghcr.io/dojoengine/dojo-dev:5d61184 + image: nondeterministickari/dojo-dev:cc6554da steps: - uses: actions/checkout@v3 - uses: Swatinem/rust-cache@v2 diff --git a/Cargo.lock b/Cargo.lock index 304e743f38..40368d83b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -149,9 +149,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "96b09b5178381e0874812a9b157f7fe84982617e48f71f4e3235482775e5b540" dependencies = [ "anstyle", "anstyle-parse", @@ -197,9 +197,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arc-swap" @@ -220,7 +220,7 @@ dependencies = [ "derivative", "hashbrown 0.13.1", "itertools 0.10.5", - "num-traits 0.2.17", + "num-traits 0.2.18", "zeroize", ] @@ -236,7 +236,7 @@ dependencies = [ "ark-std 0.3.0", "derivative", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "paste", "rustc_version 0.3.3", "zeroize", @@ -256,7 +256,7 @@ dependencies = [ "digest 0.10.7", "itertools 0.10.5", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "paste", "rustc_version 0.4.0", "zeroize", @@ -289,7 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "quote", "syn 1.0.109", ] @@ -301,7 +301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "proc-macro2", "quote", "syn 1.0.109", @@ -381,7 +381,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", ] @@ -391,7 +391,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", ] @@ -432,7 +432,7 @@ dependencies = [ "asn1-rs-impl", "displaydoc", "nom", - "num-traits 0.2.17", + "num-traits 0.2.18", "rusticata-macros", "thiserror", "time", @@ -495,13 +495,13 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c" +checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3" dependencies = [ "concurrent-queue", - "event-listener 4.0.3", - "event-listener-strategy", + "event-listener 5.1.0", + "event-listener-strategy 0.5.0", "futures-core", "pin-project-lite", ] @@ -542,7 +542,7 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.1.1", + "async-channel 2.2.0", "async-executor", "async-io 2.3.1", "async-lock 3.3.0", @@ -573,7 +573,7 @@ dependencies = [ "indexmap 2.2.5", "mime", "multer", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "pin-project-lite", "regex", @@ -593,12 +593,12 @@ checksum = "c7f329c7eb9b646a72f70c9c4b516c70867d356ec46cb00dcac8ad343fd006b0" dependencies = [ "Inflector", "async-graphql-parser", - "darling 0.20.5", + "darling 0.20.6", "proc-macro-crate 1.1.3", "proc-macro2", "quote", "strum 0.25.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -670,7 +670,7 @@ dependencies = [ "futures-io", "futures-lite 2.2.0", "parking", - "polling 3.4.0", + "polling 3.5.0", "rustix 0.38.31", "slab", "tracing", @@ -693,7 +693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" dependencies = [ "event-listener 4.0.3", - "event-listener-strategy", + "event-listener-strategy 0.4.0", "pin-project-lite", ] @@ -705,7 +705,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -753,7 +753,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -770,7 +770,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -803,7 +803,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -841,7 +841,7 @@ checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -988,7 +988,7 @@ checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", ] @@ -1027,7 +1027,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1123,7 +1123,7 @@ dependencies = [ "cairo-lang-runner", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.9.2", "ctor", "derive_more", "indexmap 2.2.5", @@ -1132,7 +1132,7 @@ dependencies = [ "log", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "phf", "serde", "serde_json", @@ -1150,7 +1150,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel 2.1.1", + "async-channel 2.2.0", "async-lock 3.3.0", "async-task", "fastrand 2.0.1", @@ -1232,14 +1232,14 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "byte-slice-cast" @@ -1399,7 +1399,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.8.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -1412,7 +1412,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -1428,7 +1428,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.8.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -1444,7 +1444,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -1461,7 +1461,7 @@ dependencies = [ "quote", "serde_json", "starknet 0.9.0", - "syn 2.0.48", + "syn 2.0.49", "thiserror", ] @@ -1473,7 +1473,7 @@ dependencies = [ "lazy_static", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", ] @@ -1486,7 +1486,7 @@ dependencies = [ "cairo-lang-utils", "indoc 2.0.4", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "parity-scale-codec", "serde", ] @@ -1644,7 +1644,7 @@ dependencies = [ "itertools 0.11.0", "log", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "salsa", "smol_str", @@ -1664,7 +1664,7 @@ dependencies = [ "colored", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "salsa", "smol_str", "unescaper", @@ -1697,7 +1697,7 @@ checksum = "fef002aac874d76492eb9577dab663f9a84fe4584b4215c7ebfda7d025fcadae" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1733,12 +1733,12 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 0.9.2", "itertools 0.11.0", "keccak", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "smol_str", "starknet-crypto 0.6.1", "thiserror", @@ -1764,7 +1764,7 @@ dependencies = [ "indoc 2.0.4", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "salsa", "smol_str", @@ -1786,7 +1786,7 @@ dependencies = [ "lalrpop", "lalrpop-util", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "regex", "salsa", "serde", @@ -1807,7 +1807,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-utils", "itertools 0.11.0", - "num-traits 0.2.17", + "num-traits 0.2.18", "thiserror", ] @@ -1822,7 +1822,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-utils", "itertools 0.11.0", - "num-traits 0.2.17", + "num-traits 0.2.18", "thiserror", ] @@ -1866,7 +1866,7 @@ dependencies = [ "indoc 2.0.4", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "thiserror", ] @@ -1908,7 +1908,7 @@ dependencies = [ "itertools 0.11.0", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "serde", "serde_json", @@ -1928,7 +1928,7 @@ dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "salsa", "smol_str", "unescaper", @@ -1967,7 +1967,7 @@ dependencies = [ "indoc 2.0.4", "itertools 0.11.0", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", ] @@ -1989,7 +1989,7 @@ dependencies = [ "cairo-lang-utils", "colored", "itertools 0.11.0", - "num-traits 0.2.17", + "num-traits 0.2.18", "rayon", ] @@ -2017,7 +2017,7 @@ dependencies = [ "itertools 0.11.0", "log", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "schemars", "serde", "time", @@ -2042,15 +2042,49 @@ dependencies = [ "num-bigint", "num-integer", "num-prime", - "num-traits 0.2.17", + "num-traits 0.2.18", + "rand", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "starknet-crypto 0.6.1", + "starknet-curve 0.4.1", + "thiserror-no-std", +] + +[[package]] +name = "cairo-vm" +version = "1.0.0-rc1" +source = "git+https://github.com/lambdaclass/cairo-vm?rev=3547089579dd74f815edbc2d1caa91e00fc8a2f7#3547089579dd74f815edbc2d1caa91e00fc8a2f7" +dependencies = [ + "anyhow", + "ark-ff 0.4.2", + "ark-std 0.4.0", + "bincode 2.0.0-rc.3", + "bitvec", + "cairo-lang-casm", + "cairo-lang-starknet", + "generic-array", + "hashbrown 0.14.3", + "hex", + "keccak", + "lazy_static", + "mimalloc", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits 0.2.18", "rand", "serde", "serde_json", "sha2 0.10.8", "sha3", "starknet-crypto 0.6.1", - "starknet-curve 0.4.0", + "starknet-types-core", "thiserror-no-std", + "zip", ] [[package]] @@ -2064,9 +2098,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" dependencies = [ "serde", ] @@ -2079,7 +2113,7 @@ checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -2164,7 +2198,7 @@ dependencies = [ "ed25519-consensus", "flex-error", "futures", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "prost 0.12.3", "prost-types 0.12.3", @@ -2189,7 +2223,7 @@ dependencies = [ "bytes", "flex-error", "num-derive", - "num-traits 0.2.17", + "num-traits 0.2.18", "prost 0.12.3", "prost-types 0.12.3", "serde", @@ -2272,14 +2306,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", - "num-traits 0.2.17", + "num-traits 0.2.18", "serde", "wasm-bindgen", "windows-targets 0.52.0", @@ -2348,9 +2382,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -2358,9 +2392,9 @@ dependencies = [ [[package]] name = "clap-verbosity-flag" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b57f73ca21b17a0352944b9bb61803b6007bd911b6cccfef7153f7f0600ac495" +checksum = "bb9b20c0dd58e4c2e991c8d203bbeb76c11304d1011659686b5b644bc29aa478" dependencies = [ "clap", "log", @@ -2368,42 +2402,42 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] name = "clap_complete" -version = "4.4.10" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3" +checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clru" @@ -2669,9 +2703,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -2700,7 +2734,7 @@ dependencies = [ "criterion-plot", "is-terminal", "itertools 0.10.5", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "oorandom", "plotters", @@ -2816,7 +2850,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2863,7 +2897,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2891,12 +2925,12 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" dependencies = [ - "darling_core 0.20.5", - "darling_macro 0.20.5", + "darling_core 0.20.6", + "darling_macro 0.20.6", ] [[package]] @@ -2909,22 +2943,22 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", - "syn 2.0.48", + "strsim 0.10.0", + "syn 2.0.49", ] [[package]] @@ -2940,13 +2974,13 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ - "darling_core 0.20.5", + "darling_core 0.20.6", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3025,7 +3059,7 @@ dependencies = [ "displaydoc", "nom", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "rusticata-macros", ] @@ -3052,18 +3086,27 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.13.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "660047478bc508c0fde22c868991eec0c40a63e48d610befef466d48e2bee574" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" dependencies = [ - "derive_builder_macro", + "derive_builder_macro 0.12.0", +] + +[[package]] +name = "derive_builder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +dependencies = [ + "derive_builder_macro 0.20.0", ] [[package]] name = "derive_builder_core" -version = "0.13.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b217e6dd1011a54d12f3b920a411b5abd44b1716ecfe94f5f2f2f7b52e08ab7" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling 0.14.4", "proc-macro2", @@ -3071,16 +3114,38 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_builder_core" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +dependencies = [ + "darling 0.20.6", + "proc-macro2", + "quote", + "syn 2.0.49", +] + [[package]] name = "derive_builder_macro" -version = "0.13.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5f77d7e20ac9153428f7ca14a88aba652adfc7a0ef0a06d654386310ef663b" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" dependencies = [ - "derive_builder_core", + "derive_builder_core 0.12.0", "syn 1.0.109", ] +[[package]] +name = "derive_builder_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +dependencies = [ + "derive_builder_core 0.20.0", + "syn 2.0.49", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -3215,7 +3280,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3279,12 +3344,12 @@ dependencies = [ "indoc 1.0.9", "itertools 0.10.5", "lazy_static", - "num-traits 0.2.17", + "num-traits 0.2.18", "once_cell", "pretty_assertions", "salsa", "scarb", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "serde_with", @@ -3335,6 +3400,7 @@ dependencies = [ "dojo-world", "jsonrpsee 0.16.3", "katana-core", + "katana-executor", "katana-primitives", "katana-rpc", "katana-rpc-api", @@ -3492,9 +3558,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" dependencies = [ "serde", ] @@ -3583,7 +3649,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3595,7 +3661,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3619,9 +3685,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55d05712b2d8d88102bc9868020c9e5c7a1f5527c452b9b97450a1d006140ba7" +checksum = "388979d208a049ffdfb22fa33b9c81942215b940910bccfe258caeb25d125cb3" dependencies = [ "serde", ] @@ -3783,7 +3849,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "syn 2.0.48", + "syn 2.0.49", "toml 0.8.10", "walkdir", ] @@ -3801,7 +3867,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3827,7 +3893,7 @@ dependencies = [ "serde", "serde_json", "strum 0.25.0", - "syn 2.0.48", + "syn 2.0.49", "tempfile", "thiserror", "tiny-keccak", @@ -3843,7 +3909,7 @@ dependencies = [ "chrono", "ethers-core", "reqwest", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -3952,7 +4018,7 @@ dependencies = [ "path-slash", "rayon", "regex", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "solang-parser", @@ -3982,6 +4048,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ad6fd685ce13acd6d9541a30f6db6567a7a24c9ffd4ba2955d29e3f22c8b27" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + [[package]] name = "event-listener-strategy" version = "0.4.0" @@ -3992,6 +4069,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "event-listener-strategy" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291" +dependencies = [ + "event-listener 5.1.0", + "pin-project-lite", +] + [[package]] name = "eyre" version = "0.6.12" @@ -4220,7 +4307,7 @@ dependencies = [ [[package]] name = "futures-bounded" version = "0.2.3" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures-timer", "futures-util", @@ -4317,7 +4404,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -4409,7 +4496,7 @@ checksum = "d4cf186fea4af17825116f72932fe52cce9a13bae39ff63b4dc0cfdb3fb4bde1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -4436,6 +4523,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ghash" version = "0.5.0" @@ -4521,7 +4620,7 @@ dependencies = [ "gix-date", "itoa", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4616,7 +4715,7 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4842,7 +4941,7 @@ checksum = "d75e7ab728059f595f6ddc1ad8771b8d6a231971ae493d9d5948ecad366ee8bb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -4889,7 +4988,7 @@ dependencies = [ "itoa", "smallvec", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -5016,7 +5115,7 @@ dependencies = [ "gix-validate", "memmap2", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -5431,7 +5530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" dependencies = [ "byteorder", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -5478,9 +5577,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -5620,9 +5719,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "human_format" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86cce260d758a9aa3d7c4b99d55c815a540f8a37514ba6046ab6be402a157cb0" +checksum = "5c3b1f728c459d27b12448862017b96ad4767b1ec2ec5e6434e99f1577f085b8" [[package]] name = "humantime" @@ -5957,9 +6056,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -6133,12 +6232,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", - "rustix 0.38.31", + "libc", "windows-sys 0.52.0", ] @@ -6230,9 +6329,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] @@ -6568,11 +6667,13 @@ version = "0.6.0-alpha.8" dependencies = [ "anyhow", "assert_matches", + "cfg-if", "clap", "clap_complete", "common", "console", "katana-core", + "katana-executor", "katana-primitives", "katana-rpc", "katana-rpc-api", @@ -6602,7 +6703,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -6612,11 +6713,11 @@ dependencies = [ "anyhow", "assert_matches", "async-trait", - "blockifier", "cairo-lang-casm", "cairo-lang-starknet", - "cairo-vm", + "cairo-vm 0.9.2", "convert_case 0.6.0", + "derive_more", "ethers", "flate2", "futures", @@ -6625,6 +6726,7 @@ dependencies = [ "katana-executor", "katana-primitives", "katana-provider", + "katana-tasks", "lazy_static", "parking_lot 0.12.1", "primitive-types", @@ -6646,9 +6748,8 @@ name = "katana-db" version = "0.6.0-alpha.8" dependencies = [ "anyhow", - "blockifier", "cairo-lang-starknet", - "cairo-vm", + "cairo-vm 0.9.2", "criterion", "katana-primitives", "page_size", @@ -6669,14 +6770,23 @@ version = "0.6.0-alpha.8" dependencies = [ "anyhow", "blockifier", - "cairo-vm", + "cairo-lang-sierra", + "cairo-vm 0.9.2", "convert_case 0.6.0", "futures", "katana-primitives", "katana-provider", + "katana-rpc-types", "parking_lot 0.12.1", + "rstest", + "rstest_reuse", + "serde_json", + "similar-asserts", "starknet 0.9.0", + "starknet-types-core", "starknet_api", + "starknet_in_rust", + "thiserror", "tokio", "tracing", ] @@ -6687,9 +6797,9 @@ version = "0.6.0-alpha.8" dependencies = [ "anyhow", "base64 0.21.7", - "blockifier", + "cairo-lang-sierra", "cairo-lang-starknet", - "cairo-vm", + "cairo-vm 0.9.2", "derive_more", "ethers", "flate2", @@ -6787,6 +6897,7 @@ dependencies = [ "futures", "jsonrpsee 0.16.3", "katana-core", + "katana-executor", "katana-primitives", "katana-provider", "serde", @@ -6916,6 +7027,28 @@ dependencies = [ "regex", ] +[[package]] +name = "lambdaworks-crypto" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d4c222d5b2fdc0faf702d3ab361d14589b097f40eac9dc550e27083483edc65" +dependencies = [ + "lambdaworks-math", + "serde", + "sha2 0.10.8", + "sha3", +] + +[[package]] +name = "lambdaworks-math" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee7dcab3968c71896b8ee4dc829147acc918cffe897af6265b1894527fe3add" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -6966,7 +7099,7 @@ dependencies = [ [[package]] name = "libp2p" version = "0.53.2" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "bytes", "either", @@ -7000,7 +7133,7 @@ dependencies = [ [[package]] name = "libp2p-allow-block-list" version = "0.3.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "libp2p-core 0.41.2 (git+https://github.com/libp2p/rust-libp2p)", "libp2p-identity", @@ -7011,7 +7144,7 @@ dependencies = [ [[package]] name = "libp2p-connection-limits" version = "0.3.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "libp2p-core 0.41.2 (git+https://github.com/libp2p/rust-libp2p)", "libp2p-identity", @@ -7050,7 +7183,7 @@ dependencies = [ [[package]] name = "libp2p-core" version = "0.41.2" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "either", "fnv", @@ -7077,7 +7210,7 @@ dependencies = [ [[package]] name = "libp2p-dns" version = "0.41.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "async-trait", "futures", @@ -7123,7 +7256,7 @@ dependencies = [ [[package]] name = "libp2p-gossipsub" version = "0.46.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "base64 0.21.7", @@ -7153,7 +7286,7 @@ dependencies = [ [[package]] name = "libp2p-identify" version = "0.44.2" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "either", @@ -7193,7 +7326,7 @@ dependencies = [ [[package]] name = "libp2p-mdns" version = "0.45.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "data-encoding", "futures", @@ -7213,7 +7346,7 @@ dependencies = [ [[package]] name = "libp2p-metrics" version = "0.14.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures", "instant", @@ -7231,7 +7364,7 @@ dependencies = [ [[package]] name = "libp2p-noise" version = "0.44.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "bytes", @@ -7256,7 +7389,7 @@ dependencies = [ [[package]] name = "libp2p-ping" version = "0.44.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "either", "futures", @@ -7273,7 +7406,7 @@ dependencies = [ [[package]] name = "libp2p-quic" version = "0.10.2" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "bytes", "futures", @@ -7296,7 +7429,7 @@ dependencies = [ [[package]] name = "libp2p-relay" version = "0.17.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "bytes", @@ -7341,7 +7474,7 @@ dependencies = [ [[package]] name = "libp2p-swarm" version = "0.44.2" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "either", "fnv", @@ -7366,18 +7499,18 @@ dependencies = [ [[package]] name = "libp2p-swarm-derive" version = "0.34.3" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "libp2p-tcp" version = "0.41.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures", "futures-timer", @@ -7393,7 +7526,7 @@ dependencies = [ [[package]] name = "libp2p-tls" version = "0.3.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures", "futures-rustls", @@ -7411,7 +7544,7 @@ dependencies = [ [[package]] name = "libp2p-upnp" version = "0.2.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures", "futures-timer", @@ -7426,7 +7559,7 @@ dependencies = [ [[package]] name = "libp2p-webrtc" version = "0.7.1-alpha" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "async-trait", "bytes", @@ -7454,7 +7587,7 @@ dependencies = [ [[package]] name = "libp2p-webrtc-utils" version = "0.2.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "bytes", @@ -7476,7 +7609,7 @@ dependencies = [ [[package]] name = "libp2p-webrtc-websys" version = "0.3.0-alpha" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "bytes", "futures", @@ -7497,7 +7630,7 @@ dependencies = [ [[package]] name = "libp2p-yamux" version = "0.45.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "either", "futures", @@ -7764,7 +7897,7 @@ checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7994,7 +8127,7 @@ dependencies = [ [[package]] name = "multistream-select" version = "0.13.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "bytes", "futures", @@ -8031,7 +8164,7 @@ dependencies = [ "matrixmultiply", "num-complex", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rawpointer", ] @@ -8236,7 +8369,7 @@ checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", "serde", ] @@ -8252,7 +8385,7 @@ dependencies = [ "libm", "num-integer", "num-iter", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", "smallvec", "zeroize", @@ -8265,7 +8398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" dependencies = [ "autocfg", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -8287,23 +8420,22 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -8314,7 +8446,7 @@ checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -8329,7 +8461,7 @@ dependencies = [ "num-bigint", "num-integer", "num-modular", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", ] @@ -8339,14 +8471,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -8380,14 +8512,14 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -8491,7 +8623,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8524,7 +8656,7 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -8533,7 +8665,7 @@ version = "3.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", ] [[package]] @@ -8588,9 +8720,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.9" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec", "bitvec", @@ -8602,11 +8734,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.9" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 1.1.3", "proc-macro2", "quote", "syn 1.0.109", @@ -8806,7 +8938,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8870,7 +9002,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8914,7 +9046,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8963,9 +9095,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" @@ -8979,7 +9111,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ - "num-traits 0.2.17", + "num-traits 0.2.18", "plotters-backend", "plotters-svg", "wasm-bindgen", @@ -9019,9 +9151,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14" +checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" dependencies = [ "cfg-if", "concurrent-queue", @@ -9143,7 +9275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9179,15 +9311,6 @@ dependencies = [ "toml 0.5.11", ] -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - [[package]] name = "proc-macro-crate" version = "3.1.0" @@ -9283,7 +9406,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9296,7 +9419,7 @@ dependencies = [ "bit-vec", "bitflags 2.4.2", "lazy_static", - "num-traits 0.2.17", + "num-traits 0.2.18", "rand", "rand_chacha", "rand_xorshift", @@ -9365,7 +9488,7 @@ dependencies = [ "prost 0.12.3", "prost-types 0.12.3", "regex", - "syn 2.0.48", + "syn 2.0.49", "tempfile", "which 4.4.2", ] @@ -9393,7 +9516,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9461,7 +9584,7 @@ dependencies = [ [[package]] name = "quick-protobuf-codec" version = "0.3.1" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "asynchronous-codec", "bytes", @@ -9840,16 +9963,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -9902,7 +10026,7 @@ dependencies = [ "digest 0.10.7", "num-bigint-dig", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "pkcs1", "pkcs8", "rand_core", @@ -9937,7 +10061,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.48", + "syn 2.0.49", "unicode-ident", ] @@ -9950,7 +10074,7 @@ dependencies = [ "quote", "rand", "rustc_version 0.4.0", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10004,7 +10128,7 @@ dependencies = [ "bytes", "fastrlp", "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "parity-scale-codec", "primitive-types", "proptest", @@ -10027,7 +10151,7 @@ name = "runner-macro" version = "0.6.0-alpha.8" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10063,7 +10187,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.21", + "semver 1.0.22", ] [[package]] @@ -10121,7 +10245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -10153,7 +10277,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -10189,7 +10313,7 @@ dependencies = [ [[package]] name = "rw-stream-sink" version = "0.4.0" -source = "git+https://github.com/libp2p/rust-libp2p#3b4c636e290628de2352949ab10c2c610bf39e0a" +source = "git+https://github.com/libp2p/rust-libp2p#261965d9fc49d14db36e20ab7dcf9c8c08cfa1a8" dependencies = [ "futures", "pin-project", @@ -10198,9 +10322,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "salsa" @@ -10274,19 +10398,52 @@ version = "0.6.0-alpha.8" dependencies = [ "anyhow", "async-trait", + "cairo-vm 0.9.2", "celestia-rpc", "celestia-types", "convert_case 0.6.0", - "ethers", "flate2", "futures", "katana-db", "katana-executor", "katana-primitives", "katana-provider", + "katana-rpc-types", "lazy_static", "parking_lot 0.12.1", "rand", + "saya-provider", + "serde", + "serde_json", + "serde_with", + "starknet 0.9.0", + "starknet-types-core", + "starknet_api", + "thiserror", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "saya-provider" +version = "0.6.0-alpha.7" +dependencies = [ + "anyhow", + "async-trait", + "auto_impl", + "convert_case 0.6.0", + "ethers", + "flate2", + "futures", + "jsonrpsee 0.16.3", + "katana-db", + "katana-executor", + "katana-primitives", + "katana-provider", + "katana-rpc-api", + "katana-rpc-types", + "lazy_static", "serde", "serde_json", "serde_with", @@ -10346,7 +10503,7 @@ dependencies = [ "create-output-dir", "data-encoding", "deno_task_shell", - "derive_builder", + "derive_builder 0.20.0", "directories", "dunce", "fs4", @@ -10367,7 +10524,7 @@ dependencies = [ "scarb-macro-interface", "scarb-metadata 1.11.1 (git+https://github.com/software-mansion/scarb?tag=v2.5.4)", "scarb-ui", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde-untagged", "serde-value", @@ -10380,7 +10537,7 @@ dependencies = [ "thiserror", "tokio", "toml 0.8.10", - "toml_edit 0.22.4", + "toml_edit 0.22.6", "tracing", "tracing-log 0.2.0", "tracing-subscriber", @@ -10420,7 +10577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abe986fc184f6af12d1e2522040ab55af2f5411a36651ea1e81aac8666751679" dependencies = [ "camino", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -10432,8 +10589,8 @@ version = "1.11.1" source = "git+https://github.com/software-mansion/scarb?tag=v2.5.4#28dee92c87e97bacefb2a300e7a102455936eeca" dependencies = [ "camino", - "derive_builder", - "semver 1.0.21", + "derive_builder 0.12.0", + "semver 1.0.22", "serde", "serde_json", "thiserror", @@ -10518,7 +10675,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -10582,9 +10739,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] @@ -10659,7 +10816,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10704,7 +10861,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10750,10 +10907,10 @@ version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ - "darling 0.20.5", + "darling 0.20.6", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10788,7 +10945,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10941,7 +11098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", - "num-traits 0.2.17", + "num-traits 0.2.18", "thiserror", "time", ] @@ -10984,9 +11141,9 @@ dependencies = [ [[package]] name = "snapbox" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73145a30df4935f50a7b13c1882bce7d194d7071ad0bcc36e7cacbf9ef16e3ec" +checksum = "4b831b6e80fbcd2889efa75b185d24005f85981431495f995292b25836519d84" dependencies = [ "anstream", "anstyle", @@ -10997,9 +11154,9 @@ dependencies = [ [[package]] name = "snapbox-macros" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ccde059aad940984ff696fe8c280900f7ea71a6fb45fce65071a3f2c40b667" +checksum = "e1c4b838b05d15ab22754068cb73500b2f3b07bf09d310e15b27f88160f1de40" dependencies = [ "anstream", ] @@ -11015,7 +11172,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek", "rand_core", - "ring 0.17.7", + "ring 0.17.8", "rustc_version 0.4.0", "sha2 0.10.8", "subtle", @@ -11106,7 +11263,7 @@ dependencies = [ "notify-debouncer-mini", "scarb", "scarb-ui", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "smol_str", @@ -11156,7 +11313,7 @@ dependencies = [ "notify-debouncer-mini", "scarb", "scarb-ui", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "smol_str", @@ -11434,6 +11591,22 @@ dependencies = [ "uuid 1.7.0", ] +[[package]] +name = "starknet" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351ffff1bcf6a1dc569a1b330dfd85779e16506e7d4a87baa8be3744cb5415a6" +dependencies = [ + "starknet-accounts 0.6.1", + "starknet-contract 0.6.0", + "starknet-core 0.7.2", + "starknet-crypto 0.6.1", + "starknet-ff", + "starknet-macros", + "starknet-providers 0.7.0", + "starknet-signers 0.5.0", +] + [[package]] name = "starknet" version = "0.8.0" @@ -11466,6 +11639,20 @@ dependencies = [ "starknet-signers 0.7.0", ] +[[package]] +name = "starknet-accounts" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7062b020f65d9da7f9dd9f1d97bfb644e881cda8ddb999799a799e6f2e408dd" +dependencies = [ + "async-trait", + "auto_impl", + "starknet-core 0.7.2", + "starknet-providers 0.7.0", + "starknet-signers 0.5.0", + "thiserror", +] + [[package]] name = "starknet-accounts" version = "0.7.0" @@ -11494,6 +11681,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "starknet-contract" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d858efc93d85de95065a5732cb3e94d0c746674964c0859aab442ffbb9de76b4" +dependencies = [ + "serde", + "serde_json", + "serde_with", + "starknet-accounts 0.6.1", + "starknet-core 0.7.2", + "starknet-providers 0.7.0", + "thiserror", +] + [[package]] name = "starknet-contract" version = "0.7.0" @@ -11524,6 +11726,24 @@ dependencies = [ "thiserror", ] +[[package]] +name = "starknet-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1683ca7c63f0642310eddedb7d35056d8306084dff323d440711065c63ed87" +dependencies = [ + "base64 0.21.7", + "flate2", + "hex", + "serde", + "serde_json", + "serde_json_pythonic", + "serde_with", + "sha3", + "starknet-crypto 0.6.1", + "starknet-ff", +] + [[package]] name = "starknet-core" version = "0.8.1" @@ -11571,7 +11791,7 @@ dependencies = [ "hmac", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rfc6979", "sha2 0.10.8", "starknet-crypto-codegen", @@ -11591,11 +11811,11 @@ dependencies = [ "hmac", "num-bigint", "num-integer", - "num-traits 0.2.17", + "num-traits 0.2.18", "rfc6979", "sha2 0.10.8", "starknet-crypto-codegen", - "starknet-curve 0.4.0", + "starknet-curve 0.4.1", "starknet-ff", "zeroize", ] @@ -11606,9 +11826,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ - "starknet-curve 0.4.0", + "starknet-curve 0.4.1", "starknet-ff", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11622,9 +11842,9 @@ dependencies = [ [[package]] name = "starknet-curve" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68a0d87ae56572abf83ddbfd44259a7c90dbeeee1629a1ffe223e7f9a8f3052" +checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" dependencies = [ "starknet-ff", ] @@ -11651,7 +11871,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c5d2964612f0ccd0a700279e33cfc98d6db04f64645ff834f3b7ec422142d7a" dependencies = [ "starknet-core 0.9.0", - "syn 2.0.48", + "syn 2.0.49", +] + +[[package]] +name = "starknet-providers" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52072c2d258bf692affeccd602613d5f6c61a6ffc84da8f191ab4a1b0a5e24d1" +dependencies = [ + "async-trait", + "auto_impl", + "ethereum-types", + "flate2", + "log", + "reqwest", + "serde", + "serde_json", + "serde_with", + "starknet-core 0.7.2", + "thiserror", + "url", ] [[package]] @@ -11694,6 +11934,22 @@ dependencies = [ "url", ] +[[package]] +name = "starknet-signers" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "347b1bfc09846aafe16d2b3a5bc2d8a2f845e2958602442182d265fbd6011c2e" +dependencies = [ + "async-trait", + "auto_impl", + "crypto-bigint", + "eth-keystore", + "rand", + "starknet-core 0.7.2", + "starknet-crypto 0.6.1", + "thiserror", +] + [[package]] name = "starknet-signers" version = "0.6.0" @@ -11726,17 +11982,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "starknet-types-core" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d53160556d1f23425100f42b3230df747ea05763efee685a2cd939dfb640701" +dependencies = [ + "bitvec", + "lambdaworks-crypto", + "lambdaworks-math", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits 0.2.18", + "serde", +] + [[package]] name = "starknet_api" -version = "0.7.0-rc.0" +version = "0.7.0-dev.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a1012226101cbe3c0483c637ca90186240f131f6af89069ae37c59073f16f9" +checksum = "88969610ab6ea9391e0e05a3e7c38acc49dc1cb49941b93ca52814075002b92f" dependencies = [ "cairo-lang-starknet", "derive_more", "hex", "indexmap 2.2.5", "once_cell", + "parity-scale-codec", + "parity-scale-codec-derive", "primitive-types", "serde", "serde_json", @@ -11746,6 +12020,45 @@ dependencies = [ "thiserror", ] +[[package]] +name = "starknet_in_rust" +version = "0.4.0" +source = "git+https://github.com/dojoengine/starknet_in_rust.git?rev=601a65e#601a65e473592d8d3c5e35a0b46868464cacef2f" +dependencies = [ + "anyhow", + "auto_impl", + "base64 0.21.7", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-runner", + "cairo-lang-sierra", + "cairo-lang-starknet", + "cairo-lang-utils", + "cairo-vm 1.0.0-rc1", + "flate2", + "getset", + "hex", + "k256", + "keccak", + "lazy_static", + "mimalloc", + "num-bigint", + "num-integer", + "num-traits 0.2.18", + "once_cell", + "p256", + "sec1", + "serde", + "serde_json", + "serde_json_pythonic", + "sha3", + "starknet 0.7.0", + "starknet-crypto 0.6.1", + "starknet_api", + "thiserror", + "tracing", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -11782,6 +12095,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "strum" version = "0.24.1" @@ -11820,7 +12139,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11883,7 +12202,7 @@ dependencies = [ "hex", "once_cell", "reqwest", - "semver 1.0.21", + "semver 1.0.22", "serde", "serde_json", "sha2 0.10.8", @@ -11905,9 +12224,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" dependencies = [ "proc-macro2", "quote", @@ -12026,27 +12345,27 @@ checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -12183,7 +12502,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -12288,7 +12607,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.4", + "toml_edit 0.22.6", ] [[package]] @@ -12310,18 +12629,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.2.5", - "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -12332,20 +12640,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap 2.2.5", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.4" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.1", ] [[package]] @@ -12421,7 +12729,7 @@ dependencies = [ "proc-macro2", "prost-build 0.12.3", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -12837,7 +13145,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -12866,7 +13174,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -13015,7 +13323,7 @@ checksum = "563b3b88238ec95680aef36bdece66896eaa7ce3c0f1b4f39d38fb2435261352" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -13108,9 +13416,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -13344,7 +13652,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-shared", ] @@ -13378,7 +13686,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13411,7 +13719,7 @@ checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -13488,7 +13796,7 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -14010,9 +14318,18 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.39" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401" dependencies = [ "memchr", ] @@ -14128,9 +14445,9 @@ checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e" [[package]] name = "xxhash-rust" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53be06678ed9e83edb1745eb72efc0bbcd7b5c3c35711a860906aed827a13d61" +checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" [[package]] name = "yamux" @@ -14195,7 +14512,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -14215,7 +14532,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4a509a3e25..e6b35536f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,10 @@ members = [ "crates/katana/storage/codecs/derive", "crates/katana/storage/db", "crates/katana/storage/provider", + "crates/katana/tasks", "crates/metrics", "crates/saya/core", + "crates/saya/provider", "crates/sozo/signers", "crates/torii/client", "crates/torii/server", @@ -68,9 +70,9 @@ dojo-world = { path = "crates/dojo-world" } # katana katana-codecs = { path = "crates/katana/storage/codecs" } katana-codecs-derive = { path = "crates/katana/storage/codecs/derive" } -katana-core = { path = "crates/katana/core" } +katana-core = { path = "crates/katana/core", default-features = false } katana-db = { path = "crates/katana/storage/db" } -katana-executor = { path = "crates/katana/executor" } +katana-executor = { path = "crates/katana/executor", default-features = false } katana-primitives = { path = "crates/katana/primitives" } katana-provider = { path = "crates/katana/storage/provider" } katana-rpc = { path = "crates/katana/rpc/rpc" } @@ -78,6 +80,7 @@ katana-rpc-api = { path = "crates/katana/rpc/rpc-api" } katana-rpc-types = { path = "crates/katana/rpc/rpc-types" } katana-rpc-types-builder = { path = "crates/katana/rpc/rpc-types-builder" } katana-runner = { path = "crates/katana/runner" } +katana-tasks = { path = "crates/katana/tasks" } # torii torii-client = { path = "crates/torii/client" } @@ -89,6 +92,7 @@ torii-server = { path = "crates/torii/server" } # saya saya-core = { path = "crates/saya/core" } +saya-provider = { path = "crates/saya/provider" } # sozo sozo-signers = { path = "crates/sozo/signers" } @@ -98,7 +102,6 @@ anyhow = "1.0.75" assert_matches = "1.5.0" async-trait = "0.1.68" base64 = "0.21.2" -blockifier = { git = "https://github.com/starkware-libs/blockifier", tag = "v0.4.0-rc9.2" } cairo-lang-compiler = "=2.5.4" cairo-lang-debug = "=2.5.4" cairo-lang-defs = "=2.5.4" @@ -166,6 +169,9 @@ tracing-subscriber = { version = "0.3.16", features = [ "env-filter", "json" ] } regex = "1.10.3" url = { version = "2.4.0", features = [ "serde" ] } +rstest = "0.18.2" +rstest_reuse = "0.6.0" + # server hyper = "0.14.27" warp = "0.3" @@ -183,9 +189,6 @@ wasm-prost = { version = "0.11.9", package = "prost" } wasm-tonic = { version = "0.9.2", default-features = false, features = [ "codegen", "gzip", "prost" ], package = "tonic" } wasm-tonic-build = { version = "0.9.2", default-features = false, features = [ "prost" ], package = "tonic-build" } -[patch."https://github.com/starkware-libs/blockifier"] -blockifier = { git = "https://github.com/dojoengine/blockifier", rev = "d38b979" } - [patch.crates-io] cairo-felt = { git = "https://github.com/dojoengine/cairo-rs.git", rev = "1031381" } cairo-vm = { git = "https://github.com/dojoengine/cairo-rs.git", rev = "1031381" } diff --git a/bin/katana/Cargo.toml b/bin/katana/Cargo.toml index 59e26a9617..774a438211 100644 --- a/bin/katana/Cargo.toml +++ b/bin/katana/Cargo.toml @@ -8,11 +8,13 @@ version.workspace = true [dependencies] anyhow.workspace = true +cfg-if = "1.0.0" clap.workspace = true clap_complete.workspace = true common.workspace = true console.workspace = true katana-core.workspace = true +katana-executor.workspace = true katana-primitives.workspace = true katana-rpc-api.workspace = true katana-rpc.workspace = true @@ -30,7 +32,11 @@ url.workspace = true assert_matches = "1.5.0" [features] -default = [ "jemalloc", "messaging" ] +default = [ "blockifier", "jemalloc", "messaging" ] + +blockifier = [ "katana-executor/blockifier" ] +sir = [ "katana-executor/sir" ] + jemalloc = [ "metrics/jemalloc" ] messaging = [ "katana-core/messaging" ] starknet-messaging = [ "katana-core/starknet-messaging", "messaging" ] diff --git a/bin/katana/src/args.rs b/bin/katana/src/args.rs index 09fe81b18e..c583434afe 100644 --- a/bin/katana/src/args.rs +++ b/bin/katana/src/args.rs @@ -218,7 +218,7 @@ impl KatanaArgs { } pub fn server_config(&self) -> ServerConfig { - let mut apis = vec![ApiKind::Starknet, ApiKind::Katana, ApiKind::Torii]; + let mut apis = vec![ApiKind::Starknet, ApiKind::Katana, ApiKind::Torii, ApiKind::Saya]; // only enable `katana` API in dev mode if self.dev { apis.push(ApiKind::Dev); diff --git a/bin/katana/src/main.rs b/bin/katana/src/main.rs index 8a2b524426..0c62ce949a 100644 --- a/bin/katana/src/main.rs +++ b/bin/katana/src/main.rs @@ -5,8 +5,13 @@ use std::sync::Arc; use clap::{CommandFactory, Parser}; use clap_complete::{generate, Shell}; use console::Style; +use katana_core::constants::MAX_RECURSION_DEPTH; +use katana_core::env::get_default_vm_resource_fee_cost; use katana_core::sequencer::KatanaSequencer; -use katana_primitives::contract::{ClassHash, ContractAddress}; +use katana_executor::SimulationFlag; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::ContractAddress; +use katana_primitives::env::{CfgEnv, FeeTokenAddressses}; use katana_primitives::genesis::allocation::GenesisAccountAlloc; use katana_primitives::genesis::Genesis; use katana_rpc::{spawn, NodeHandle}; @@ -38,7 +43,40 @@ async fn main() -> Result<(), Box> { let sequencer_config = args.sequencer_config(); let starknet_config = args.starknet_config(); - let sequencer = Arc::new(KatanaSequencer::new(sequencer_config, starknet_config).await?); + let cfg_env = CfgEnv { + chain_id: starknet_config.env.chain_id, + vm_resource_fee_cost: get_default_vm_resource_fee_cost(), + invoke_tx_max_n_steps: starknet_config.env.invoke_max_steps, + validate_max_n_steps: starknet_config.env.validate_max_steps, + max_recursion_depth: MAX_RECURSION_DEPTH, + fee_token_addresses: FeeTokenAddressses { + eth: starknet_config.genesis.fee_token.address, + strk: Default::default(), + }, + }; + + let simulation_flags = SimulationFlag { + skip_validate: starknet_config.disable_validate, + skip_fee_transfer: starknet_config.disable_fee, + ..Default::default() + }; + + cfg_if::cfg_if! { + if #[cfg(all(feature = "blockifier", feature = "sir"))] { + compile_error!("Cannot enable both `blockifier` and `sir` features at the same time"); + } else if #[cfg(feature = "blockifier")] { + use katana_executor::implementation::blockifier::BlockifierFactory; + let executor_factory = BlockifierFactory::new(cfg_env, simulation_flags); + } else if #[cfg(feature = "sir")] { + use katana_executor::implementation::sir::NativeExecutorFactory; + let executor_factory = NativeExecutorFactory::new(cfg_env, simulation_flags); + } else { + compile_error!("At least one of the following features must be enabled: blockifier, sir"); + } + } + + let sequencer = + Arc::new(KatanaSequencer::new(executor_factory, sequencer_config, starknet_config).await?); let NodeHandle { addr, handle, .. } = spawn(Arc::clone(&sequencer), server_config).await?; if !args.silent { diff --git a/bin/saya/src/args/mod.rs b/bin/saya/src/args/mod.rs index 149e80c093..48e73a9d97 100644 --- a/bin/saya/src/args/mod.rs +++ b/bin/saya/src/args/mod.rs @@ -49,7 +49,7 @@ pub struct SayaArgs { impl SayaArgs { pub fn init_logging(&self) -> Result<(), Box> { - const DEFAULT_LOG_FILTER: &str = "info,saya_core=trace"; + const DEFAULT_LOG_FILTER: &str = "info,saya_core=trace,blockchain=trace,provider=trace"; let builder = fmt::Subscriber::builder().with_env_filter( EnvFilter::try_from_default_env().or(EnvFilter::try_new(DEFAULT_LOG_FILTER))?, diff --git a/bin/saya/src/main.rs b/bin/saya/src/main.rs index 07a2af69d7..9ed0796eb9 100644 --- a/bin/saya/src/main.rs +++ b/bin/saya/src/main.rs @@ -16,7 +16,7 @@ async fn main() -> Result<(), Box> { let config = args.try_into()?; print_intro(&config); - let saya = Saya::new(config).await?; + let mut saya = Saya::new(config).await?; saya.start().await?; // Wait until Ctrl + C is pressed, then shutdown diff --git a/crates/dojo-test-utils/Cargo.toml b/crates/dojo-test-utils/Cargo.toml index a69649fd02..8cdbb727bf 100644 --- a/crates/dojo-test-utils/Cargo.toml +++ b/crates/dojo-test-utils/Cargo.toml @@ -18,6 +18,7 @@ dojo-lang = { path = "../dojo-lang" } dojo-world = { path = "../dojo-world", features = [ "manifest", "migration" ] } jsonrpsee = { version = "0.16.2", features = [ "server" ] } katana-core = { path = "../katana/core" } +katana-executor = { workspace = true, features = [ "blockifier" ] } katana-primitives = { path = "../katana/primitives" } katana-rpc = { path = "../katana/rpc/rpc" } katana-rpc-api = { path = "../katana/rpc/rpc-api" } diff --git a/crates/dojo-test-utils/src/sequencer.rs b/crates/dojo-test-utils/src/sequencer.rs index 9e006c0e59..7017c6cc3c 100644 --- a/crates/dojo-test-utils/src/sequencer.rs +++ b/crates/dojo-test-utils/src/sequencer.rs @@ -2,9 +2,14 @@ use std::sync::Arc; use jsonrpsee::core::Error; pub use katana_core::backend::config::{Environment, StarknetConfig}; +use katana_core::constants::MAX_RECURSION_DEPTH; +use katana_core::env::get_default_vm_resource_fee_cost; use katana_core::sequencer::KatanaSequencer; pub use katana_core::sequencer::SequencerConfig; +use katana_executor::implementation::blockifier::BlockifierFactory; +use katana_executor::SimulationFlag; use katana_primitives::chain::ChainId; +use katana_primitives::env::{CfgEnv, FeeTokenAddressses}; use katana_rpc::config::ServerConfig; use katana_rpc::{spawn, NodeHandle}; use katana_rpc_api::ApiKind; @@ -26,13 +31,33 @@ pub struct TestSequencer { url: Url, handle: NodeHandle, account: TestAccount, - pub sequencer: Arc, + pub sequencer: Arc>, } impl TestSequencer { pub async fn start(config: SequencerConfig, starknet_config: StarknetConfig) -> Self { + let cfg_env = CfgEnv { + chain_id: starknet_config.env.chain_id, + vm_resource_fee_cost: get_default_vm_resource_fee_cost(), + invoke_tx_max_n_steps: starknet_config.env.invoke_max_steps, + validate_max_n_steps: starknet_config.env.validate_max_steps, + max_recursion_depth: MAX_RECURSION_DEPTH, + fee_token_addresses: FeeTokenAddressses { + eth: starknet_config.genesis.fee_token.address, + strk: Default::default(), + }, + }; + + let simulation_flags = SimulationFlag { + skip_validate: starknet_config.disable_validate, + skip_fee_transfer: starknet_config.disable_fee, + ..Default::default() + }; + + let executor_factory = BlockifierFactory::new(cfg_env, simulation_flags); + let sequencer = Arc::new( - KatanaSequencer::new(config, starknet_config) + KatanaSequencer::new(executor_factory, config, starknet_config) .await .expect("Failed to create sequencer"), ); @@ -43,7 +68,13 @@ impl TestSequencer { port: 0, host: "127.0.0.1".into(), max_connections: 100, - apis: vec![ApiKind::Starknet, ApiKind::Katana, ApiKind::Torii, ApiKind::Dev], + apis: vec![ + ApiKind::Starknet, + ApiKind::Katana, + ApiKind::Dev, + ApiKind::Saya, + ApiKind::Torii, + ], }, ) .await diff --git a/crates/katana/core/Cargo.toml b/crates/katana/core/Cargo.toml index 7b084a45ac..2669286bdc 100644 --- a/crates/katana/core/Cargo.toml +++ b/crates/katana/core/Cargo.toml @@ -8,18 +8,19 @@ version.workspace = true [dependencies] katana-db = { path = "../storage/db" } -katana-executor = { path = "../executor" } +katana-executor.workspace = true katana-primitives = { path = "../primitives" } katana-provider = { path = "../storage/provider" } +katana-tasks.workspace = true anyhow.workspace = true async-trait.workspace = true -blockifier.workspace = true cairo-lang-casm = "2.3.1" cairo-lang-starknet = "2.3.1" cairo-vm.workspace = true convert_case.workspace = true -ethers = "2.0.11" +derive_more.workspace = true +ethers = { version = "2.0.11", optional = true } flate2.workspace = true futures.workspace = true lazy_static = "1.4.0" @@ -42,5 +43,5 @@ hex = "0.4.3" tempfile = "3.8.1" [features] -messaging = [ ] +messaging = [ "ethers" ] starknet-messaging = [ ] diff --git a/crates/katana/core/src/backend/contract.rs b/crates/katana/core/src/backend/contract.rs index 7e6e9ddf37..57966dc61c 100644 --- a/crates/katana/core/src/backend/contract.rs +++ b/crates/katana/core/src/backend/contract.rs @@ -1,7 +1,7 @@ -use blockifier::execution::contract_class::ContractClassV0; +use katana_primitives::class::DeprecatedCompiledClass; use starknet::core::types::FlattenedSierraClass; pub enum StarknetContract { - Legacy(ContractClassV0), + Legacy(DeprecatedCompiledClass), Sierra(FlattenedSierraClass), } diff --git a/crates/katana/core/src/backend/mod.rs b/crates/katana/core/src/backend/mod.rs index 7f1a4039b7..979c0903d2 100644 --- a/crates/katana/core/src/backend/mod.rs +++ b/crates/katana/core/src/backend/mod.rs @@ -1,19 +1,17 @@ use std::sync::Arc; +use katana_executor::ExecutorFactory; use katana_primitives::block::{ Block, FinalityStatus, GasPrices, Header, PartialHeader, SealedBlockWithStatus, }; use katana_primitives::chain::ChainId; -use katana_primitives::env::{BlockEnv, CfgEnv, FeeTokenAddressses}; -use katana_primitives::receipt::Receipt; +use katana_primitives::env::BlockEnv; use katana_primitives::state::StateUpdatesWithDeclaredClasses; -use katana_primitives::transaction::TxWithHash; use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::FieldElement; use katana_provider::providers::fork::ForkedProvider; use katana_provider::providers::in_memory::InMemoryProvider; use katana_provider::traits::block::{BlockHashProvider, BlockWriter}; -use katana_provider::traits::state::{StateFactoryProvider, StateProvider}; use parking_lot::RwLock; use starknet::core::types::{BlockId, BlockStatus, MaybePendingBlockWithTxHashes}; use starknet::core::utils::parse_cairo_short_string; @@ -27,12 +25,11 @@ pub mod storage; use self::config::StarknetConfig; use self::storage::Blockchain; -use crate::constants::MAX_RECURSION_DEPTH; -use crate::env::{get_default_vm_resource_fee_cost, BlockContextGenerator}; -use crate::service::block_producer::{BlockProductionError, MinedBlockOutcome}; +use crate::env::BlockContextGenerator; +use crate::service::block_producer::{BlockProductionError, MinedBlockOutcome, TxWithOutcome}; use crate::utils::get_current_timestamp; -pub struct Backend { +pub struct Backend { /// The config used to generate the backend. pub config: StarknetConfig, /// stores all block related data in memory @@ -41,15 +38,15 @@ pub struct Backend { pub chain_id: ChainId, /// The block context generator. pub block_context_generator: RwLock, + + pub executor_factory: Arc, } -impl Backend { - pub async fn new(mut config: StarknetConfig) -> Self { +impl Backend { + pub async fn new(executor_factory: Arc, mut config: StarknetConfig) -> Self { let block_context_generator = config.block_context_generator(); - let (blockchain, chain_id): (Blockchain, ChainId) = if let Some(forked_url) = - &config.fork_rpc_url - { + let blockchain: Blockchain = if let Some(forked_url) = &config.fork_rpc_url { let provider = Arc::new(JsonRpcClient::new(HttpTransport::new(forked_url.clone()))); let forked_chain_id = provider.chain_id().await.unwrap(); @@ -99,54 +96,47 @@ impl Backend { ) .expect("able to create forked blockchain"); - (blockchain, forked_chain_id.into()) + config.env.chain_id = forked_chain_id.into(); + blockchain } else if let Some(db_path) = &config.db_dir { - ( - Blockchain::new_with_db(db_path, &config.genesis) - .expect("able to create blockchain from db"), - config.env.chain_id, - ) + Blockchain::new_with_db(db_path, &config.genesis) + .expect("able to create blockchain from db") } else { - let blockchain = Blockchain::new_with_genesis(InMemoryProvider::new(), &config.genesis) - .expect("able to create blockchain from genesis block"); - - (blockchain, config.env.chain_id) + Blockchain::new_with_genesis(InMemoryProvider::new(), &config.genesis) + .expect("able to create blockchain from genesis block") }; Self { - chain_id, + chain_id: config.env.chain_id, blockchain, config, + executor_factory, block_context_generator: RwLock::new(block_context_generator), } } - /// Mines a new block based on the provided execution outcome. - /// This method should only be called by the - /// [IntervalBlockProducer](crate::service::block_producer::IntervalBlockProducer) when the node - /// is running in `interval` mining mode. - pub fn mine_pending_block( - &self, - block_env: &BlockEnv, - tx_receipt_pairs: Vec<(TxWithHash, Receipt)>, - state_updates: StateUpdatesWithDeclaredClasses, - ) -> Result<(MinedBlockOutcome, Box), BlockProductionError> { - let outcome = self.do_mine_block(block_env, tx_receipt_pairs, state_updates)?; - let new_state = StateFactoryProvider::latest(&self.blockchain.provider())?; - Ok((outcome, new_state)) - } - pub fn do_mine_block( &self, block_env: &BlockEnv, - tx_receipt_pairs: Vec<(TxWithHash, Receipt)>, + txs_outcomes: Vec, state_updates: StateUpdatesWithDeclaredClasses, ) -> Result { - let (txs, receipts): (Vec, Vec) = tx_receipt_pairs.into_iter().unzip(); + let mut txs = vec![]; + let mut receipts = vec![]; + let mut execs = vec![]; + + for t in txs_outcomes { + txs.push(t.tx); + receipts.push(t.receipt); + execs.push(t.exec_info); + } let prev_hash = BlockHashProvider::latest_hash(self.blockchain.provider())?; + let block_number = block_env.number; + let tx_count = txs.len(); let partial_header = PartialHeader { + number: block_number, parent_hash: prev_hash, version: CURRENT_STARKNET_VERSION, timestamp: block_env.timestamp, @@ -157,10 +147,7 @@ impl Backend { }, }; - let tx_count = txs.len(); - let block_number = block_env.number; - - let header = Header::new(partial_header, block_number, FieldElement::ZERO); + let header = Header::new(partial_header, FieldElement::ZERO); let block = Block { header, body: txs }.seal(); let block = SealedBlockWithStatus { block, status: FinalityStatus::AcceptedOnL2 }; @@ -169,6 +156,7 @@ impl Backend { block, state_updates, receipts, + execs, )?; info!(target: "backend", "ā›ļø Block {block_number} mined with {tx_count} transactions"); @@ -194,21 +182,6 @@ impl Backend { block_env.l1_gas_prices = self.config.env.gas_price.clone(); } - /// Retrieves the chain configuration environment values. - pub(crate) fn chain_cfg_env(&self) -> CfgEnv { - CfgEnv { - chain_id: self.chain_id, - vm_resource_fee_cost: get_default_vm_resource_fee_cost(), - invoke_tx_max_n_steps: self.config.env.invoke_max_steps, - validate_max_n_steps: self.config.env.validate_max_steps, - max_recursion_depth: MAX_RECURSION_DEPTH, - fee_token_addresses: FeeTokenAddressses { - eth: self.config.genesis.fee_token.address, - strk: Default::default(), - }, - } - } - pub fn mine_empty_block( &self, block_env: &BlockEnv, @@ -220,6 +193,9 @@ impl Backend { #[cfg(test)] mod tests { + use std::sync::Arc; + + use katana_executor::implementation::noop::NoopExecutorFactory; use katana_primitives::genesis::Genesis; use katana_provider::traits::block::{BlockNumberProvider, BlockProvider}; use katana_provider::traits::env::BlockEnvProvider; @@ -236,8 +212,8 @@ mod tests { } } - async fn create_test_backend() -> Backend { - Backend::new(create_test_starknet_config()).await + async fn create_test_backend() -> Backend { + Backend::new(Arc::new(NoopExecutorFactory::default()), create_test_starknet_config()).await } #[tokio::test] diff --git a/crates/katana/core/src/backend/storage.rs b/crates/katana/core/src/backend/storage.rs index 1324791ed4..06cbb71358 100644 --- a/crates/katana/core/src/backend/storage.rs +++ b/crates/katana/core/src/backend/storage.rs @@ -12,7 +12,8 @@ use katana_provider::traits::env::BlockEnvProvider; use katana_provider::traits::state::{StateFactoryProvider, StateRootProvider, StateWriter}; use katana_provider::traits::state_update::StateUpdateProvider; use katana_provider::traits::transaction::{ - ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionsProviderExt, + ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionTraceProvider, + TransactionsProviderExt, }; use katana_provider::BlockchainProvider; @@ -21,6 +22,7 @@ pub trait Database: + BlockWriter + TransactionProvider + TransactionStatusProvider + + TransactionTraceProvider + TransactionsProviderExt + ReceiptProvider + StateUpdateProvider @@ -40,6 +42,7 @@ impl Database for T where + BlockWriter + TransactionProvider + TransactionStatusProvider + + TransactionTraceProvider + TransactionsProviderExt + ReceiptProvider + StateUpdateProvider @@ -119,7 +122,13 @@ impl Blockchain { block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, ) -> Result { - BlockWriter::insert_block_with_states_and_receipts(&provider, block, states, vec![])?; + BlockWriter::insert_block_with_states_and_receipts( + &provider, + block, + states, + vec![], + vec![], + )?; Ok(Self::new(provider)) } } @@ -245,6 +254,7 @@ mod tests { dummy_block.clone(), StateUpdatesWithDeclaredClasses::default(), vec![Receipt::Invoke(InvokeTxReceipt::default())], + vec![], ) .unwrap(); diff --git a/crates/katana/core/src/sequencer.rs b/crates/katana/core/src/sequencer.rs index 05ca68dd09..790be10c69 100644 --- a/crates/katana/core/src/sequencer.rs +++ b/crates/katana/core/src/sequencer.rs @@ -4,17 +4,12 @@ use std::slice::Iter; use std::sync::Arc; use anyhow::Result; -use blockifier::block_context::BlockContext; -use blockifier::execution::errors::{EntryPointExecutionError, PreExecutionError}; -use blockifier::transaction::errors::TransactionExecutionError; -use katana_executor::blockifier::state::StateRefDb; -use katana_executor::blockifier::utils::{block_context_from_envs, EntryPointCall}; -use katana_executor::blockifier::PendingState; +use katana_executor::ExecutorFactory; use katana_primitives::block::{BlockHash, BlockHashOrNumber, BlockIdOrTag, BlockNumber}; use katana_primitives::chain::ChainId; -use katana_primitives::contract::{ - ClassHash, CompiledContractClass, ContractAddress, Nonce, StorageKey, StorageValue, -}; +use katana_primitives::class::{ClassHash, CompiledClass}; +use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; +use katana_primitives::env::BlockEnv; use katana_primitives::event::{ContinuationToken, ContinuationTokenError}; use katana_primitives::receipt::Event; use katana_primitives::transaction::{ExecutableTxWithHash, TxHash, TxWithHash}; @@ -28,16 +23,14 @@ use katana_provider::traits::state::{StateFactoryProvider, StateProvider}; use katana_provider::traits::transaction::{ ReceiptProvider, TransactionProvider, TransactionsProviderExt, }; -use starknet::core::types::{ - BlockTag, EmittedEvent, EventsPage, FeeEstimate, SimulatedTransaction, -}; +use starknet::core::types::{BlockTag, EmittedEvent, EventsPage}; use crate::backend::config::StarknetConfig; use crate::backend::contract::StarknetContract; use crate::backend::Backend; use crate::pool::TransactionPool; use crate::sequencer_error::SequencerError; -use crate::service::block_producer::{BlockProducer, BlockProducerMode}; +use crate::service::block_producer::{BlockProducer, BlockProducerMode, PendingExecutor}; #[cfg(feature = "messaging")] use crate::service::messaging::MessagingConfig; #[cfg(feature = "messaging")] @@ -54,39 +47,30 @@ pub struct SequencerConfig { pub messaging: Option, } -pub struct KatanaSequencer { +pub struct KatanaSequencer { pub config: SequencerConfig, pub pool: Arc, - pub backend: Arc, - pub block_producer: BlockProducer, + pub backend: Arc>, + pub block_producer: Arc>, } -impl KatanaSequencer { +impl KatanaSequencer { pub async fn new( + executor_factory: EF, config: SequencerConfig, starknet_config: StarknetConfig, ) -> anyhow::Result { - let backend = Arc::new(Backend::new(starknet_config).await); + let executor_factory = Arc::new(executor_factory); + let backend = Arc::new(Backend::new(executor_factory.clone(), starknet_config).await); let pool = Arc::new(TransactionPool::new()); let miner = TransactionMiner::new(pool.add_listener()); - let state = StateFactoryProvider::latest(backend.blockchain.provider()) - .map(StateRefDb::new) - .unwrap(); - let block_producer = if config.block_time.is_some() || config.no_mining { - let block_num = backend.blockchain.provider().latest_number()?; - - let mut block_env = - backend.blockchain.provider().block_env_at(block_num.into())?.unwrap(); - backend.update_block_env(&mut block_env); - let cfg_env = backend.chain_cfg_env(); - if let Some(interval) = config.block_time { - BlockProducer::interval(Arc::clone(&backend), state, interval, (block_env, cfg_env)) + BlockProducer::interval(Arc::clone(&backend), interval) } else { - BlockProducer::on_demand(Arc::clone(&backend), state, (block_env, cfg_env)) + BlockProducer::on_demand(Arc::clone(&backend)) } } else { BlockProducer::instant(Arc::clone(&backend)) @@ -99,6 +83,8 @@ impl KatanaSequencer { None }; + let block_producer = Arc::new(block_producer); + tokio::spawn(NodeService { miner, pool: Arc::clone(&pool), @@ -111,51 +97,49 @@ impl KatanaSequencer { } /// Returns the pending state if the sequencer is running in _interval_ mode. Otherwise `None`. - pub fn pending_state(&self) -> Option> { + pub fn pending_executor(&self) -> Option { match &*self.block_producer.inner.read() { BlockProducerMode::Instant(_) => None, - BlockProducerMode::Interval(producer) => Some(producer.state()), + BlockProducerMode::Interval(producer) => Some(producer.executor()), } } - pub fn block_producer(&self) -> &BlockProducer { + pub fn block_producer(&self) -> &BlockProducer { &self.block_producer } - pub fn backend(&self) -> &Backend { + pub fn backend(&self) -> &Backend { &self.backend } - pub fn block_execution_context_at( - &self, - block_id: BlockIdOrTag, - ) -> SequencerResult> { + pub fn block_env_at(&self, block_id: BlockIdOrTag) -> SequencerResult> { let provider = self.backend.blockchain.provider(); - let cfg_env = self.backend().chain_cfg_env(); - if let BlockIdOrTag::Tag(BlockTag::Pending) = block_id { - if let Some(state) = self.pending_state() { - let (block_env, _) = state.block_execution_envs(); - return Ok(Some(block_context_from_envs(&block_env, &cfg_env))); + if BlockIdOrTag::Tag(BlockTag::Pending) == block_id { + if let Some(exec) = self.pending_executor() { + return Ok(Some(exec.read().block_env())); } } - let block_num = match block_id { + match block_id { BlockIdOrTag::Tag(BlockTag::Pending) | BlockIdOrTag::Tag(BlockTag::Latest) => { - provider.latest_number()? + let num = provider.latest_number()?; + provider + .block_env_at(num.into())? + .map(Some) + .ok_or(SequencerError::BlockNotFound(block_id)) } BlockIdOrTag::Hash(hash) => provider - .block_number_by_hash(hash)? - .ok_or(SequencerError::BlockNotFound(block_id))?, - - BlockIdOrTag::Number(num) => num, - }; - - provider - .block_env_at(block_num.into())? - .map(|block_env| Some(block_context_from_envs(&block_env, &cfg_env))) - .ok_or(SequencerError::BlockNotFound(block_id)) + .block_env_at(hash.into())? + .map(Some) + .ok_or(SequencerError::BlockNotFound(block_id)), + + BlockIdOrTag::Number(num) => provider + .block_env_at(num.into())? + .map(Some) + .ok_or(SequencerError::BlockNotFound(block_id)), + } } pub fn state(&self, block_id: &BlockIdOrTag) -> SequencerResult> { @@ -168,8 +152,8 @@ impl KatanaSequencer { } BlockIdOrTag::Tag(BlockTag::Pending) => { - if let Some(state) = self.pending_state() { - Ok(Box::new(state.state.clone())) + if let Some(exec) = self.pending_executor() { + Ok(Box::new(exec.read().state())) } else { let state = StateFactoryProvider::latest(provider)?; Ok(state) @@ -192,54 +176,6 @@ impl KatanaSequencer { self.pool.add_transaction(tx); } - pub fn estimate_fee( - &self, - transactions: Vec, - block_id: BlockIdOrTag, - skip_validate: bool, - ) -> SequencerResult> { - let state = self.state(&block_id)?; - - let block_context = self - .block_execution_context_at(block_id)? - .ok_or_else(|| SequencerError::BlockNotFound(block_id))?; - - // If the node is run with transaction validation disabled, then we should not validate - // transactions when estimating the fee even if the `SKIP_VALIDATE` flag is not set. - let should_validate = !(skip_validate || self.backend.config.disable_validate); - - katana_executor::blockifier::utils::estimate_fee( - transactions.into_iter(), - block_context, - state, - should_validate, - ) - .map_err(SequencerError::TransactionExecution) - } - - pub fn simulate_transactions( - &self, - transactions: Vec, - block_id: BlockIdOrTag, - validate: bool, - charge_fee: bool, - ) -> SequencerResult> { - let state = self.state(&block_id)?; - - let block_context = self - .block_execution_context_at(block_id)? - .ok_or_else(|| SequencerError::BlockNotFound(block_id))?; - - katana_executor::blockifier::utils::simulate_transactions( - transactions, - &block_context, - state, - validate, - charge_fee, - ) - .map_err(SequencerError::TransactionExecution) - } - pub fn block_hash_and_number(&self) -> SequencerResult<(BlockHash, BlockNumber)> { let provider = self.backend.blockchain.provider(); let hash = BlockHashProvider::latest_hash(provider)?; @@ -269,8 +205,8 @@ impl KatanaSequencer { }; match class { - CompiledContractClass::V0(class) => Ok(Some(StarknetContract::Legacy(class))), - CompiledContractClass::V1(_) => { + CompiledClass::Deprecated(class) => Ok(Some(StarknetContract::Legacy(class))), + CompiledClass::Class(_) => { let class = ContractClassProvider::sierra_class(&state, class_hash)? .map(StarknetContract::Sierra); Ok(class) @@ -308,8 +244,9 @@ impl KatanaSequencer { let provider = self.backend.blockchain.provider(); let count = match block_id { - BlockIdOrTag::Tag(BlockTag::Pending) => match self.pending_state() { - Some(state) => Some(state.executed_txs.read().len() as u64), + BlockIdOrTag::Tag(BlockTag::Pending) => match self.pending_executor() { + Some(exec) => Some(exec.read().transactions().len() as u64), + None => { let hash = BlockHashProvider::latest_hash(provider)?; TransactionProvider::transaction_count_by_block(provider, hash.into())? @@ -343,40 +280,14 @@ impl KatanaSequencer { Ok(nonce) } - pub fn call( - &self, - request: EntryPointCall, - block_id: BlockIdOrTag, - ) -> SequencerResult> { - let state = self.state(&block_id)?; - - let block_context = self - .block_execution_context_at(block_id)? - .ok_or_else(|| SequencerError::BlockNotFound(block_id))?; - - let retdata = katana_executor::blockifier::utils::call(request, block_context, state) - .map_err(|e| match e { - TransactionExecutionError::ExecutionError(exe) => match exe { - EntryPointExecutionError::PreExecutionError( - PreExecutionError::UninitializedStorageAddress(addr), - ) => SequencerError::ContractNotFound(addr.into()), - _ => SequencerError::EntryPointExecution(exe), - }, - _ => SequencerError::TransactionExecution(e), - })?; - - Ok(retdata) - } - pub fn transaction(&self, hash: &TxHash) -> SequencerResult> { let tx = TransactionProvider::transaction_by_hash(self.backend.blockchain.provider(), *hash)?; let tx @ Some(_) = tx else { - return Ok(self.pending_state().as_ref().and_then(|state| { - state - .executed_txs - .read() + return Ok(self.pending_executor().as_ref().and_then(|exec| { + exec.read() + .transactions() .iter() .find_map(|tx| if tx.0.hash == *hash { Some(tx.0.clone()) } else { None }) })); @@ -517,8 +428,8 @@ impl KatanaSequencer { } pub fn has_pending_transactions(&self) -> bool { - if let Some(ref pending) = self.pending_state() { - !pending.executed_txs.read().is_empty() + if let Some(ref exec) = self.pending_executor() { + !exec.read().transactions().is_empty() } else { false } @@ -586,6 +497,7 @@ fn filter_events_by_params( #[cfg(test)] mod tests { + use katana_executor::implementation::noop::NoopExecutorFactory; use katana_provider::traits::block::BlockNumberProvider; use super::{KatanaSequencer, SequencerConfig}; @@ -593,7 +505,10 @@ mod tests { #[tokio::test] async fn init_interval_block_producer_with_correct_block_env() { + let executor_factory = NoopExecutorFactory::default(); + let sequencer = KatanaSequencer::new( + executor_factory, SequencerConfig { no_mining: true, ..Default::default() }, StarknetConfig::default(), ) @@ -603,7 +518,7 @@ mod tests { let provider = sequencer.backend.blockchain.provider(); let latest_num = provider.latest_number().unwrap(); - let producer_block_env = sequencer.pending_state().unwrap().block_execution_envs().0; + let producer_block_env = sequencer.pending_executor().unwrap().read().block_env(); assert_eq!( producer_block_env.number, diff --git a/crates/katana/core/src/sequencer_error.rs b/crates/katana/core/src/sequencer_error.rs index cdf611d3f3..cf84bffed6 100644 --- a/crates/katana/core/src/sequencer_error.rs +++ b/crates/katana/core/src/sequencer_error.rs @@ -1,5 +1,3 @@ -use blockifier::execution::errors::EntryPointExecutionError; -use blockifier::transaction::errors::TransactionExecutionError; use katana_primitives::block::BlockIdOrTag; use katana_primitives::contract::ContractAddress; use katana_primitives::event::ContinuationTokenError; @@ -13,10 +11,6 @@ pub enum SequencerError { ContractNotFound(ContractAddress), #[error("State for block {0:?} not found.")] StateNotFound(BlockIdOrTag), - #[error(transparent)] - TransactionExecution(#[from] TransactionExecutionError), - #[error(transparent)] - EntryPointExecution(#[from] EntryPointExecutionError), #[error("Wait for pending transactions.")] PendingTransactions, #[error(transparent)] diff --git a/crates/katana/core/src/service/block_producer.rs b/crates/katana/core/src/service/block_producer.rs index 56055ad142..8d8251e74f 100644 --- a/crates/katana/core/src/service/block_producer.rs +++ b/crates/katana/core/src/service/block_producer.rs @@ -8,24 +8,20 @@ use std::time::Duration; use futures::channel::mpsc::{channel, Receiver, Sender}; use futures::stream::{Stream, StreamExt}; use futures::FutureExt; -use katana_executor::blockifier::outcome::TxReceiptWithExecInfo; -use katana_executor::blockifier::state::{CachedStateWrapper, StateRefDb}; -use katana_executor::blockifier::utils::{ - block_context_from_envs, get_state_update_from_cached_state, -}; -use katana_executor::blockifier::{PendingState, TransactionExecutor}; -use katana_primitives::block::BlockHashOrNumber; -use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_executor::{BlockExecutor, ExecutionOutput, ExecutionResult, ExecutorFactory}; +use katana_primitives::block::{BlockHashOrNumber, ExecutableBlock, PartialHeader}; use katana_primitives::receipt::Receipt; -use katana_primitives::state::StateUpdatesWithDeclaredClasses; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{ExecutableTxWithHash, TxWithHash}; +use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_provider::error::ProviderError; -use katana_provider::traits::block::BlockNumberProvider; +use katana_provider::traits::block::{BlockHashProvider, BlockNumberProvider}; use katana_provider::traits::env::BlockEnvProvider; use katana_provider::traits::state::StateFactoryProvider; +use katana_tasks::{BlockingTaskPool, BlockingTaskResult}; use parking_lot::RwLock; use tokio::time::{interval_at, Instant, Interval}; -use tracing::{trace, warn}; +use tracing::{error, info, trace, warn}; use crate::backend::Backend; @@ -33,68 +29,70 @@ use crate::backend::Backend; pub enum BlockProductionError { #[error(transparent)] Provider(#[from] ProviderError), + + #[error("block mining task cancelled")] + BlockMiningTaskCancelled, + + #[error("transaction execution task cancelled")] + ExecutionTaskCancelled, + + #[error("transaction execution error: {0}")] + TransactionExecutionError(#[from] katana_executor::ExecutorError), } pub struct MinedBlockOutcome { pub block_number: u64, } -type ServiceFuture = Pin + Send + Sync>>; +#[derive(Debug, Clone)] +pub struct TxWithOutcome { + pub tx: TxWithHash, + pub receipt: Receipt, + pub exec_info: TxExecInfo, +} + +type ServiceFuture = Pin> + Send + Sync>>; type BlockProductionResult = Result; type BlockProductionFuture = ServiceFuture; + +type TxExecutionResult = Result, BlockProductionError>; +type TxExecutionFuture = ServiceFuture; + type BlockProductionWithTxnsFuture = - ServiceFuture, MinedBlockOutcome), BlockProductionError>>; -pub type TxWithHashAndReceiptPair = (TxWithHash, Receipt); + ServiceFuture), BlockProductionError>>; /// The type which responsible for block production. #[must_use = "BlockProducer does nothing unless polled"] -#[derive(Clone)] -pub struct BlockProducer { +pub struct BlockProducer { /// The inner mode of mining. - pub inner: Arc>, + pub inner: RwLock>, } -impl BlockProducer { +impl BlockProducer { /// Creates a block producer that mines a new block every `interval` milliseconds. - pub fn interval( - backend: Arc, - initial_state: StateRefDb, - interval: u64, - block_exec_envs: (BlockEnv, CfgEnv), - ) -> Self { + pub fn interval(backend: Arc>, interval: u64) -> Self { Self { - inner: Arc::new(RwLock::new(BlockProducerMode::Interval(IntervalBlockProducer::new( - backend, - initial_state, - interval, - block_exec_envs, - )))), + inner: RwLock::new(BlockProducerMode::Interval(IntervalBlockProducer::new( + backend, interval, + ))), } } /// Creates a new block producer that will only be possible to mine by calling the /// `katana_generateBlock` RPC method. - pub fn on_demand( - backend: Arc, - initial_state: StateRefDb, - block_exec_envs: (BlockEnv, CfgEnv), - ) -> Self { + pub fn on_demand(backend: Arc>) -> Self { Self { - inner: Arc::new(RwLock::new(BlockProducerMode::Interval( - IntervalBlockProducer::new_no_mining(backend, initial_state, block_exec_envs), + inner: RwLock::new(BlockProducerMode::Interval(IntervalBlockProducer::new_no_mining( + backend, ))), } } /// Creates a block producer that mines a new block as soon as there are ready transactions in /// the transactions pool. - pub fn instant(backend: Arc) -> Self { - Self { - inner: Arc::new(RwLock::new(BlockProducerMode::Instant(InstantBlockProducer::new( - backend, - )))), - } + pub fn instant(backend: Arc>) -> Self { + Self { inner: RwLock::new(BlockProducerMode::Instant(InstantBlockProducer::new(backend))) } } pub(super) fn queue(&self, transactions: Vec) { @@ -117,18 +115,15 @@ impl BlockProducer { // Handler for the `katana_generateBlock` RPC method. pub fn force_mine(&self) { - trace!(target: "miner", "force mining"); + trace!(target: "miner", "scheduling force block mining"); let mut mode = self.inner.write(); match &mut *mode { BlockProducerMode::Instant(producer) => producer.force_mine(), BlockProducerMode::Interval(producer) => producer.force_mine(), } } -} -impl Stream for BlockProducer { - type Item = BlockProductionResult; - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + pub(super) fn poll_next(&self, cx: &mut Context<'_>) -> Poll> { let mut mode = self.inner.write(); match &mut *mode { BlockProducerMode::Instant(producer) => producer.poll_next_unpin(cx), @@ -150,32 +145,37 @@ impl Stream for BlockProducer { /// block producer will execute all the transactions in the mempool and mine a new block with the /// resulting state. The block context is only updated every time a new block is mined as opposed to /// updating it when the block is opened (in _interval_ mode). -pub enum BlockProducerMode { - Interval(IntervalBlockProducer), - Instant(InstantBlockProducer), +pub enum BlockProducerMode { + Interval(IntervalBlockProducer), + Instant(InstantBlockProducer), } -pub struct IntervalBlockProducer { +#[derive(Clone, derive_more::Deref)] +pub struct PendingExecutor(#[deref] Arc>>>); + +impl PendingExecutor { + fn new(executor: Box>) -> Self { + Self(Arc::new(RwLock::new(executor))) + } +} + +pub struct IntervalBlockProducer { /// The interval at which new blocks are mined. interval: Option, - backend: Arc, + backend: Arc>, /// Single active future that mines a new block - block_mining: Option, + ongoing_mining: Option, /// Backlog of sets of transactions ready to be mined queued: VecDeque>, - /// The state of the pending block after executing all the transactions within the interval. - state: Arc, + executor: PendingExecutor, + blocking_task_spawner: BlockingTaskPool, + ongoing_execution: Option, /// Listeners notified when a new executed tx is added. - tx_execution_listeners: RwLock>>>, + tx_execution_listeners: RwLock>>>, } -impl IntervalBlockProducer { - pub fn new( - backend: Arc, - db: StateRefDb, - interval: u64, - block_exec_envs: (BlockEnv, CfgEnv), - ) -> Self { +impl IntervalBlockProducer { + pub fn new(backend: Arc>, interval: u64) -> Self { let interval = { let duration = Duration::from_millis(interval); let mut interval = interval_at(Instant::now() + duration, duration); @@ -183,12 +183,24 @@ impl IntervalBlockProducer { interval }; - let state = Arc::new(PendingState::new(db, block_exec_envs.0, block_exec_envs.1)); + let provider = backend.blockchain.provider(); + + let latest_num = provider.latest_number().unwrap(); + let mut block_env = provider.block_env_at(latest_num.into()).unwrap().unwrap(); + backend.update_block_env(&mut block_env); + + let state = provider.latest().unwrap(); + let executor = backend.executor_factory.with_state_and_block_env(state, block_env); + let executor = PendingExecutor::new(executor); + + let blocking_task_spawner = BlockingTaskPool::new().unwrap(); Self { backend, - state, - block_mining: None, + executor, + ongoing_mining: None, + blocking_task_spawner, + ongoing_execution: None, interval: Some(interval), queued: VecDeque::default(), tx_execution_listeners: RwLock::new(vec![]), @@ -198,94 +210,121 @@ impl IntervalBlockProducer { /// Creates a new [IntervalBlockProducer] with no `interval`. This mode will not produce blocks /// for every fixed interval, although it will still execute all queued transactions and /// keep hold of the pending state. - pub fn new_no_mining( - backend: Arc, - db: StateRefDb, - block_exec_envs: (BlockEnv, CfgEnv), - ) -> Self { - let state = Arc::new(PendingState::new(db, block_exec_envs.0, block_exec_envs.1)); + pub fn new_no_mining(backend: Arc>) -> Self { + let provider = backend.blockchain.provider(); + + let latest_num = provider.latest_number().unwrap(); + let mut block_env = provider.block_env_at(latest_num.into()).unwrap().unwrap(); + backend.update_block_env(&mut block_env); + + let state = provider.latest().unwrap(); + let executor = backend.executor_factory.with_state_and_block_env(state, block_env); + let executor = PendingExecutor::new(executor); + + let blocking_task_spawner = BlockingTaskPool::new().unwrap(); Self { - state, backend, + executor, interval: None, - block_mining: None, + ongoing_mining: None, queued: VecDeque::default(), + blocking_task_spawner, + ongoing_execution: None, tx_execution_listeners: RwLock::new(vec![]), } } - pub fn state(&self) -> Arc { - self.state.clone() + pub fn executor(&self) -> PendingExecutor { + self.executor.clone() } /// Force mine a new block. It will only able to mine if there is no ongoing mining process. - pub fn force_mine(&self) { - if self.block_mining.is_none() { - let outcome = self.outcome(); - let _ = Self::do_mine(outcome, self.backend.clone(), self.state.clone()); - } else { - trace!(target: "miner", "unable to force mine while a mining process is running") + pub fn force_mine(&mut self) { + match Self::do_mine(self.executor.clone(), self.backend.clone()) { + Ok(outcome) => { + info!(target: "miner", "force mined block {}", outcome.block_number); + self.executor = + self.create_new_executor_for_next_block().expect("fail to create executor"); + } + Err(e) => { + error!(target: "miner", "failed to force mine: {e}"); + } } } fn do_mine( - state_updates: StateUpdatesWithDeclaredClasses, - backend: Arc, - pending_state: Arc, - ) -> BlockProductionResult { + executor: PendingExecutor, + backend: Arc>, + ) -> Result { + let executor = &mut executor.write(); + trace!(target: "miner", "creating new block"); - let (txs, _) = pending_state.take_txs_all(); - let tx_receipt_pairs = - txs.into_iter().map(|(tx, rct)| (tx, rct.receipt)).collect::>(); + let block_env = executor.block_env(); + let ExecutionOutput { states, transactions } = executor.take_execution_output()?; - let (mut block_env, cfg_env) = pending_state.block_execution_envs(); + let transactions = transactions + .into_iter() + .filter_map(|(tx, res)| match res { + ExecutionResult::Failed { .. } => None, + ExecutionResult::Success { receipt, trace, .. } => { + Some(TxWithOutcome { tx, receipt, exec_info: trace }) + } + }) + .collect::>(); - let (outcome, new_state) = - backend.mine_pending_block(&block_env, tx_receipt_pairs, state_updates)?; + let outcome = backend.do_mine_block(&block_env, transactions, states)?; trace!(target: "miner", "created new block: {}", outcome.block_number); - backend.update_block_env(&mut block_env); - pending_state.reset_state(StateRefDb(new_state), block_env, cfg_env); - Ok(outcome) } - fn execute_transactions(&self, transactions: Vec) { - let txs = transactions.iter().map(TxWithHash::from); - - let block_context = block_context_from_envs( - &self.state.block_envs.read().0, - &self.state.block_envs.read().1, - ); - - let results = { - TransactionExecutor::new( - &self.state.state, - &block_context, - !self.backend.config.disable_fee, - !self.backend.config.disable_validate, - transactions.clone().into_iter(), - ) - .with_error_log() - .with_events_log() - .with_resources_log() - .zip(txs) - .filter_map(|(res, tx)| { - let Ok(info) = res else { return None }; - let receipt = TxReceiptWithExecInfo::new(&tx, info); - Some((tx, receipt)) + fn execute_transactions( + executor: PendingExecutor, + transactions: Vec, + ) -> TxExecutionResult { + let executor = &mut executor.write(); + + let new_txs_count = transactions.len(); + executor.execute_transactions(transactions)?; + + let txs = executor.transactions(); + let total_txs = txs.len(); + + // Take only the results of the newly executed transactions + let results = txs + .iter() + .skip(total_txs - new_txs_count) + .filter_map(|(tx, res)| match res { + ExecutionResult::Failed { .. } => None, + ExecutionResult::Success { receipt, trace, .. } => Some(TxWithOutcome { + tx: tx.clone(), + receipt: receipt.clone(), + exec_info: trace.clone(), + }), }) - .collect::>() - }; + .collect::>(); - self.state.executed_txs.write().extend(results.clone()); - self.notify_listener(results.into_iter().map(|(tx, info)| (tx, info.receipt)).collect()); + Ok(results) } - pub fn add_listener(&self) -> Receiver> { + fn create_new_executor_for_next_block(&self) -> Result { + let backend = &self.backend; + let provider = backend.blockchain.provider(); + + let latest_num = provider.latest_number()?; + let updated_state = provider.latest()?; + + let mut block_env = provider.block_env_at(latest_num.into())?.unwrap(); + backend.update_block_env(&mut block_env); + + let executor = backend.executor_factory.with_state_and_block_env(updated_state, block_env); + Ok(PendingExecutor::new(executor)) + } + + pub fn add_listener(&self) -> Receiver> { const TX_LISTENER_BUFFER_SIZE: usize = 2048; let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE); self.tx_execution_listeners.write().push(tx); @@ -293,7 +332,7 @@ impl IntervalBlockProducer { } /// notifies all listeners about the transaction - fn notify_listener(&self, txs: Vec) { + fn notify_listener(&self, txs: Vec) { let mut listener = self.tx_execution_listeners.write(); // this is basically a retain but with mut reference for n in (0..listener.len()).rev() { @@ -317,13 +356,9 @@ impl IntervalBlockProducer { } } } - - fn outcome(&self) -> StateUpdatesWithDeclaredClasses { - get_state_update_from_cached_state(&self.state.state) - } } -impl Stream for IntervalBlockProducer { +impl Stream for IntervalBlockProducer { // mined block outcome and the new state type Item = BlockProductionResult; @@ -331,32 +366,82 @@ impl Stream for IntervalBlockProducer { let pin = self.get_mut(); if let Some(interval) = &mut pin.interval { - if interval.poll_tick(cx).is_ready() && pin.block_mining.is_none() { + // mine block if the interval is over + if interval.poll_tick(cx).is_ready() && pin.ongoing_mining.is_none() { + let executor = pin.executor.clone(); let backend = pin.backend.clone(); - let outcome = pin.outcome(); - let state = pin.state.clone(); - - pin.block_mining = Some(Box::pin(async move { - tokio::task::spawn_blocking(|| Self::do_mine(outcome, backend, state)) - .await - .unwrap() - })); + let fut = pin.blocking_task_spawner.spawn(|| Self::do_mine(executor, backend)); + pin.ongoing_mining = Some(Box::pin(fut)); } } - // only execute transactions if there is no mining in progress - if !pin.queued.is_empty() && pin.block_mining.is_none() { - let transactions = pin.queued.pop_front().expect("not empty; qed"); - pin.execute_transactions(transactions); + loop { + if !pin.queued.is_empty() + && pin.ongoing_execution.is_none() + && pin.ongoing_mining.is_none() + { + let executor = pin.executor.clone(); + let transactions: Vec = + std::mem::take(&mut pin.queued).into_iter().flatten().collect(); + + let fut = pin + .blocking_task_spawner + .spawn(|| Self::execute_transactions(executor, transactions)); + + pin.ongoing_execution = Some(Box::pin(fut)); + } + + // poll the ongoing execution if any + if let Some(mut execution) = pin.ongoing_execution.take() { + if let Poll::Ready(executor) = execution.poll_unpin(cx) { + match executor { + Ok(Ok(txs)) => { + pin.notify_listener(txs); + continue; + } + + Ok(Err(e)) => { + return Poll::Ready(Some(Err(e))); + } + + Err(_) => { + return Poll::Ready(Some(Err( + BlockProductionError::ExecutionTaskCancelled, + ))); + } + } + } else { + pin.ongoing_execution = Some(execution); + } + } + + break; } - // poll the mining future - if let Some(mut mining) = pin.block_mining.take() { - // reset the executor for the next block - if let Poll::Ready(outcome) = mining.poll_unpin(cx) { - return Poll::Ready(Some(outcome)); + // poll the mining future if any + if let Some(mut mining) = pin.ongoing_mining.take() { + if let Poll::Ready(res) = mining.poll_unpin(cx) { + match res { + Ok(outcome) => { + match pin.create_new_executor_for_next_block() { + Ok(executor) => { + pin.executor = executor; + } + + Err(e) => return Poll::Ready(Some(Err(e))), + } + + return Poll::Ready(Some(outcome)); + } + + Err(_) => { + return Poll::Ready(Some(Err( + BlockProductionError::BlockMiningTaskCancelled, + ))); + } + } } else { - pin.block_mining = Some(mining) + pin.ongoing_mining = Some(mining); } } @@ -364,23 +449,26 @@ impl Stream for IntervalBlockProducer { } } -pub struct InstantBlockProducer { +pub struct InstantBlockProducer { /// Holds the backend if no block is being mined - backend: Arc, + backend: Arc>, /// Single active future that mines a new block block_mining: Option, /// Backlog of sets of transactions ready to be mined queued: VecDeque>, + + blocking_task_pool: BlockingTaskPool, /// Listeners notified when a new executed tx is added. - tx_execution_listeners: RwLock>>>, + tx_execution_listeners: RwLock>>>, } -impl InstantBlockProducer { - pub fn new(backend: Arc) -> Self { +impl InstantBlockProducer { + pub fn new(backend: Arc>) -> Self { Self { backend, block_mining: None, queued: VecDeque::default(), + blocking_task_pool: BlockingTaskPool::new().unwrap(), tx_execution_listeners: RwLock::new(vec![]), } } @@ -395,58 +483,55 @@ impl InstantBlockProducer { } fn do_mine( - backend: Arc, + backend: Arc>, transactions: Vec, - ) -> Result<(Vec, MinedBlockOutcome), BlockProductionError> { + ) -> Result<(MinedBlockOutcome, Vec), BlockProductionError> { trace!(target: "miner", "creating new block"); let provider = backend.blockchain.provider(); - let cfg_env = backend.chain_cfg_env(); let latest_num = provider.latest_number()?; let mut block_env = provider.block_env_at(BlockHashOrNumber::Num(latest_num))?.unwrap(); backend.update_block_env(&mut block_env); - let block_context = block_context_from_envs(&block_env, &cfg_env); - - let latest_state = StateFactoryProvider::latest(backend.blockchain.provider())?; - let state = CachedStateWrapper::new(StateRefDb(latest_state)); - - let txs = transactions.iter().map(TxWithHash::from); - - let tx_receipt_pairs: Vec = TransactionExecutor::new( - &state, - &block_context, - !backend.config.disable_fee, - !backend.config.disable_validate, - transactions.clone().into_iter(), - ) - .with_error_log() - .with_events_log() - .with_resources_log() - .zip(txs) - .filter_map(|(res, tx)| { - if let Ok(info) = res { - let info = TxReceiptWithExecInfo::new(&tx, info); - Some((tx, info.receipt)) - } else { - None - } - }) - .collect(); + let parent_hash = provider.latest_hash()?; + let latest_state = provider.latest()?; + + let mut executor = backend.executor_factory.with_state(latest_state); + + let block = ExecutableBlock { + body: transactions, + header: PartialHeader { + parent_hash, + number: block_env.number, + timestamp: block_env.timestamp, + gas_prices: block_env.l1_gas_prices.clone(), + sequencer_address: block_env.sequencer_address, + version: CURRENT_STARKNET_VERSION, + }, + }; - let outcome = backend.do_mine_block( - &block_env, - tx_receipt_pairs.clone(), - get_state_update_from_cached_state(&state), - )?; + executor.execute_block(block)?; + + let ExecutionOutput { states, transactions } = executor.take_execution_output()?; + let txs_outcomes = transactions + .into_iter() + .filter_map(|(tx, res)| match res { + ExecutionResult::Success { receipt, trace, .. } => { + Some(TxWithOutcome { tx, receipt, exec_info: trace }) + } + _ => None, + }) + .collect::>(); + + let outcome = backend.do_mine_block(&block_env, txs_outcomes.clone(), states)?; trace!(target: "miner", "created new block: {}", outcome.block_number); - Ok((tx_receipt_pairs, outcome)) + Ok((outcome, txs_outcomes)) } - pub fn add_listener(&self) -> Receiver> { + pub fn add_listener(&self) -> Receiver> { const TX_LISTENER_BUFFER_SIZE: usize = 2048; let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE); self.tx_execution_listeners.write().push(tx); @@ -454,7 +539,7 @@ impl InstantBlockProducer { } /// notifies all listeners about the transaction - fn notify_listener(&self, txs: Vec) { + fn notify_listener(&self, txs: Vec) { let mut listener = self.tx_execution_listeners.write(); // this is basically a retain but with mut reference for n in (0..listener.len()).rev() { @@ -480,7 +565,7 @@ impl InstantBlockProducer { } } -impl Stream for InstantBlockProducer { +impl Stream for InstantBlockProducer { // mined block outcome and the new state type Item = Result; @@ -491,26 +576,32 @@ impl Stream for InstantBlockProducer { let transactions = pin.queued.pop_front().expect("not empty; qed"); let backend = pin.backend.clone(); - pin.block_mining = Some(Box::pin(async move { - tokio::task::spawn_blocking(|| Self::do_mine(backend, transactions)).await.unwrap() - })); + pin.block_mining = Some(Box::pin( + pin.blocking_task_pool.spawn(|| Self::do_mine(backend, transactions)), + )); } // poll the mining future if let Some(mut mining) = pin.block_mining.take() { - match mining.poll_unpin(cx) { - Poll::Ready(Ok((txs, outcome))) => { - pin.notify_listener(txs); - return Poll::Ready(Some(Ok(outcome))); - } + if let Poll::Ready(outcome) = mining.poll_unpin(cx) { + match outcome { + Ok(Ok((outcome, txs))) => { + pin.notify_listener(txs); + return Poll::Ready(Some(Ok(outcome))); + } - Poll::Ready(Err(e)) => { - return Poll::Ready(Some(Err(e))); - } + Ok(Err(e)) => { + return Poll::Ready(Some(Err(e))); + } - Poll::Pending => { - pin.block_mining = Some(mining); + Err(_) => { + return Poll::Ready(Some(Err( + BlockProductionError::ExecutionTaskCancelled, + ))); + } } + } else { + pin.block_mining = Some(mining) } } diff --git a/crates/katana/core/src/service/messaging/service.rs b/crates/katana/core/src/service/messaging/service.rs index 379a866dce..ea0d124904 100644 --- a/crates/katana/core/src/service/messaging/service.rs +++ b/crates/katana/core/src/service/messaging/service.rs @@ -4,6 +4,7 @@ use std::task::{Context, Poll}; use std::time::Duration; use futures::{Future, FutureExt, Stream}; +use katana_executor::ExecutorFactory; use katana_primitives::block::BlockHashOrNumber; use katana_primitives::receipt::MessageToL1; use katana_primitives::transaction::{ExecutableTxWithHash, L1HandlerTx, TxHash}; @@ -20,10 +21,10 @@ type MessagingFuture = Pin + Send>>; type MessageGatheringFuture = MessagingFuture>; type MessageSettlingFuture = MessagingFuture>>; -pub struct MessagingService { +pub struct MessagingService { /// The interval at which the service will perform the messaging operations. interval: Interval, - backend: Arc, + backend: Arc>, pool: Arc, /// The messenger mode the service is running in. messenger: Arc, @@ -37,13 +38,13 @@ pub struct MessagingService { msg_send_fut: Option, } -impl MessagingService { +impl MessagingService { /// Initializes a new instance from a configuration file's path. /// Will panic on failure to avoid continuing with invalid configuration. pub async fn new( config: MessagingConfig, pool: Arc, - backend: Arc, + backend: Arc>, ) -> anyhow::Result { let gather_from_block = config.from_block; let interval = interval_from_seconds(config.interval); @@ -72,7 +73,7 @@ impl MessagingService { async fn gather_messages( messenger: Arc, pool: Arc, - backend: Arc, + backend: Arc>, from_block: u64, ) -> MessengerResult<(u64, usize)> { // 200 avoids any possible rejection from RPC with possibly lot's of messages. @@ -113,7 +114,7 @@ impl MessagingService { async fn send_messages( block_num: u64, - backend: Arc, + backend: Arc>, messenger: Arc, ) -> MessengerResult> { let Some(messages) = ReceiptProvider::receipts_by_block( @@ -167,7 +168,7 @@ pub enum MessagingOutcome { }, } -impl Stream for MessagingService { +impl Stream for MessagingService { type Item = MessagingOutcome; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { diff --git a/crates/katana/core/src/service/mod.rs b/crates/katana/core/src/service/mod.rs index 3b803f83da..5758b0a924 100644 --- a/crates/katana/core/src/service/mod.rs +++ b/crates/katana/core/src/service/mod.rs @@ -7,9 +7,10 @@ use std::task::{Context, Poll}; use futures::channel::mpsc::Receiver; use futures::stream::{Fuse, Stream, StreamExt}; +use katana_executor::ExecutorFactory; use katana_primitives::transaction::ExecutableTxWithHash; use starknet::core::types::FieldElement; -use tracing::{error, trace}; +use tracing::{error, info}; use self::block_producer::BlockProducer; use crate::pool::TransactionPool; @@ -26,19 +27,19 @@ use self::messaging::{MessagingOutcome, MessagingService}; /// This service is basically an endless future that continuously polls the miner which returns /// transactions for the next block, then those transactions are handed off to the [BlockProducer] /// to construct a new block. -pub struct NodeService { +pub struct NodeService { /// the pool that holds all transactions pub(crate) pool: Arc, /// creates new blocks - pub(crate) block_producer: BlockProducer, + pub(crate) block_producer: Arc>, /// the miner responsible to select transactions from the `poolĀ“ pub(crate) miner: TransactionMiner, /// The messaging service #[cfg(feature = "messaging")] - pub(crate) messaging: Option, + pub(crate) messaging: Option>, } -impl Future for NodeService { +impl Future for NodeService { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { @@ -49,10 +50,10 @@ impl Future for NodeService { while let Poll::Ready(Some(outcome)) = messaging.poll_next_unpin(cx) { match outcome { MessagingOutcome::Gather { msg_count, .. } => { - trace!(target: "node", "collected {msg_count} messages from settlement chain"); + info!(target: "node", "collected {msg_count} messages from settlement chain"); } MessagingOutcome::Send { msg_count, .. } => { - trace!(target: "node", "sent {msg_count} messages to the settlement chain"); + info!(target: "node", "sent {msg_count} messages to the settlement chain"); } } } @@ -61,10 +62,10 @@ impl Future for NodeService { // this drives block production and feeds new sets of ready transactions to the block // producer loop { - while let Poll::Ready(Some(res)) = pin.block_producer.poll_next_unpin(cx) { + while let Poll::Ready(Some(res)) = pin.block_producer.poll_next(cx) { match res { Ok(outcome) => { - trace!(target: "node", "mined block {}", outcome.block_number) + info!(target: "node", "mined block {}", outcome.block_number) } Err(err) => { diff --git a/crates/katana/core/tests/sequencer.rs b/crates/katana/core/tests/sequencer.rs index d4d2225e82..8fa521afb2 100644 --- a/crates/katana/core/tests/sequencer.rs +++ b/crates/katana/core/tests/sequencer.rs @@ -1,6 +1,7 @@ use ethers::types::U256; use katana_core::backend::config::{Environment, StarknetConfig}; use katana_core::sequencer::{KatanaSequencer, SequencerConfig}; +use katana_executor::implementation::noop::NoopExecutorFactory; use katana_primitives::genesis::allocation::DevAllocationsGenerator; use katana_primitives::genesis::constant::DEFAULT_PREFUNDED_ACCOUNT_BALANCE; use katana_primitives::genesis::Genesis; @@ -26,9 +27,10 @@ fn create_test_sequencer_config() -> (SequencerConfig, StarknetConfig) { ) } -async fn create_test_sequencer() -> KatanaSequencer { +async fn create_test_sequencer() -> KatanaSequencer { + let executor_factory = NoopExecutorFactory::new(); let (sequencer_config, starknet_config) = create_test_sequencer_config(); - KatanaSequencer::new(sequencer_config, starknet_config).await.unwrap() + KatanaSequencer::new(executor_factory, sequencer_config, starknet_config).await.unwrap() } #[tokio::test] diff --git a/crates/katana/executor/.env.cairo-native b/crates/katana/executor/.env.cairo-native new file mode 100644 index 0000000000..d47b8fabea --- /dev/null +++ b/crates/katana/executor/.env.cairo-native @@ -0,0 +1,3 @@ +export MLIR_SYS_170_PREFIX=/opt/homebrew/opt/llvm@17 +export LLVM_SYS_170_PREFIX=/opt/homebrew/opt/llvm@17 +export TABLEGEN_170_PREFIX=/opt/homebrew/opt/llvm@17 diff --git a/crates/katana/executor/Cargo.toml b/crates/katana/executor/Cargo.toml index 50211e7f9c..22830c4933 100644 --- a/crates/katana/executor/Cargo.toml +++ b/crates/katana/executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -description = "Katana execution engine. This crate provides implementations for executing transactions." +description = "Katana execution engine. This crate provides abstractions and implementations for transaction execution." edition.workspace = true name = "katana-executor" version.workspace = true @@ -7,18 +7,41 @@ version.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -katana-primitives = { path = "../primitives" } -katana-provider = { path = "../storage/provider" } +katana-primitives.workspace = true +katana-provider.workspace = true -anyhow.workspace = true -cairo-vm.workspace = true convert_case.workspace = true futures.workspace = true parking_lot.workspace = true +serde_json.workspace = true starknet.workspace = true +starknet_api.workspace = true +thiserror.workspace = true tracing.workspace = true # blockifier deps -blockifier.workspace = true -starknet_api.workspace = true +blockifier = { git = "https://github.com/dojoengine/blockifier", rev = "d38b979", optional = true } +cairo-vm = { workspace = true, optional = true } + +# starknet_in_rust deps +cairo-lang-sierra = { workspace = true, optional = true } +sir = { package = "starknet_in_rust", git = "https://github.com/dojoengine/starknet_in_rust.git", rev = "601a65e", optional = true } +starknet-types-core = { version = "0.0.9", optional = true } + +[dev-dependencies] +anyhow.workspace = true +cairo-vm.workspace = true +katana-provider.workspace = true +katana-rpc-types.workspace = true +rstest.workspace = true +rstest_reuse.workspace = true +serde_json.workspace = true +similar-asserts.workspace = true tokio.workspace = true + +[features] +default = [ "blockifier", "sir" ] + +blockifier = [ "dep:blockifier", "dep:cairo-vm" ] +# native = [ "sir", "sir/cairo-native" ] +sir = [ "dep:sir", "dep:starknet-types-core" ] diff --git a/crates/katana/executor/README.md b/crates/katana/executor/README.md new file mode 100644 index 0000000000..6533c5fdfa --- /dev/null +++ b/crates/katana/executor/README.md @@ -0,0 +1,41 @@ +## katana-executor + +This crate provides a set of abstractions for performing transaction executions in Katana. It includes [implementations](./src/implementation/) for the different execution engines that Katana supports: + +1. [blockifier](https://github.com/dojoengine/blockifier) by StarkWare +2. [starknet_in_rust](https://github.com/dojoengine/starknet_in_rust) by LambdaClass. + +They are feature-gated under `blockifier` and `sir` features respectively and enabled by **default**. + +This crate also includes a [*noop*](./src/implementation/noop.rs) implementation for testing purposes. + +### Cairo Native support + +The [starknet_in_rust](./src/implementation/sir/) executor can be integrated with Cairo Native, which makes the execution of sierra programs possible through native machine code. To use it, you must enable the `native` feature when using this crate as a dependency, + +```toml +[dependencies] +katana-executor = { .., features = [ "native" ] } +``` + +and the following needs to be setup: + +LLVM 17 needs to be installed and the `MLIR_SYS_170_PREFIX` and `TABLEGEN_170_PREFIX` environment variable needs to point to said installation. + +In macOS, run + +```console +brew install llvm@17 +``` + +and export the following environment variables: + +```bash +export MLIR_SYS_170_PREFIX=/opt/homebrew/opt/llvm@17 +export LLVM_SYS_170_PREFIX=/opt/homebrew/opt/llvm@17 +export TABLEGEN_170_PREFIX=/opt/homebrew/opt/llvm@17 +``` + +and you're set. + + diff --git a/crates/katana/executor/src/abstraction/error.rs b/crates/katana/executor/src/abstraction/error.rs new file mode 100644 index 0000000000..e077c004dd --- /dev/null +++ b/crates/katana/executor/src/abstraction/error.rs @@ -0,0 +1,62 @@ +use katana_primitives::class::ClassHash; +use katana_primitives::contract::{ContractAddress, Nonce}; +use katana_primitives::FieldElement; + +/// Errors that can be returned by the executor. +#[derive(Debug, thiserror::Error)] +pub enum ExecutorError {} + +/// Errors that can occur during the transaction execution. +#[derive(Debug, Clone, thiserror::Error)] +pub enum ExecutionError { + #[error("contract constructor execution error: {0}")] + ConstructorExecutionFailed(Box), + + #[error("class with hash {0:#x} is already declared")] + ClassAlreadyDeclared(ClassHash), + + #[error("entry point {0:#x} not found in contract")] + EntryPointNotFound(FieldElement), + + #[error("invalid input: {input_descriptor}; {info}")] + InvalidInput { input_descriptor: String, info: String }, + + #[error("execution failed due to recursion depth exceeded")] + RecursionDepthExceeded, + + #[error("contract with address {0} is not deployed")] + ContractNotDeployed(ContractAddress), + + #[error("invalid transaction nonce: expected {expected} got {actual}")] + InvalidNonce { actual: Nonce, expected: Nonce }, + + #[error( + "insufficient balance: max fee {max_fee} exceeds account balance u256({balance_low}, \ + {balance_high})" + )] + InsufficientBalance { max_fee: u128, balance_low: FieldElement, balance_high: FieldElement }, + + #[error("actual fee {max_fee} exceeded transaction max fee {actual_fee}")] + ActualFeeExceedsMaxFee { max_fee: u128, actual_fee: u128 }, + + #[error("transaction max fee ({max_fee:#x}) is too low; min max fee is {min:#x}")] + MaxFeeTooLow { min: u128, max_fee: u128 }, + + #[error("class with hash {0:#x} is not declared")] + UndeclaredClass(ClassHash), + + #[error("fee transfer error: {0}")] + FeeTransferError(String), + + #[error("entry point execution error: {reason}")] + ExecutionFailed { reason: String }, + + #[error("transaction validation error: {0}")] + TransactionValidationFailed(Box), + + #[error("transaction reverted: {revert_error}")] + TransactionReverted { revert_error: String }, + + #[error("{0}")] + Other(String), +} diff --git a/crates/katana/executor/src/abstraction/executor.rs b/crates/katana/executor/src/abstraction/executor.rs new file mode 100644 index 0000000000..7f2e6957c9 --- /dev/null +++ b/crates/katana/executor/src/abstraction/executor.rs @@ -0,0 +1,73 @@ +use katana_primitives::block::ExecutableBlock; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::transaction::{ExecutableTxWithHash, TxWithHash}; +use katana_primitives::FieldElement; +use katana_provider::traits::state::StateProvider; + +use crate::{ + EntryPointCall, ExecutionError, ExecutionOutput, ExecutionResult, ExecutorResult, + ResultAndStates, SimulationFlag, +}; + +/// A type that can create [BlockExecutor] instance. +pub trait ExecutorFactory: Send + Sync + 'static { + /// Construct a new [BlockExecutor] with the given state. + fn with_state<'a, P>(&self, state: P) -> Box + 'a> + where + P: StateProvider + 'a; + + /// Construct a new [BlockExecutor] with the given state and block environment values. + fn with_state_and_block_env<'a, P>( + &self, + state: P, + block_env: BlockEnv, + ) -> Box + 'a> + where + P: StateProvider + 'a; + + /// Returns the configuration environment of the factory. + fn cfg(&self) -> &CfgEnv; +} + +/// An executor that can execute a block of transactions. +pub trait BlockExecutor<'a>: ExecutorExt + Send + Sync { + /// Executes the given block. + fn execute_block(&mut self, block: ExecutableBlock) -> ExecutorResult<()>; + + fn execute_transactions( + &mut self, + transactions: Vec, + ) -> ExecutorResult<()>; + + /// Takes the output state of the executor. + fn take_execution_output(&mut self) -> ExecutorResult; + + /// Returns the current state of the executor. + fn state(&self) -> Box; + + /// Returns the transactions that have been executed. + fn transactions(&self) -> &[(TxWithHash, ExecutionResult)]; + + /// Returns the current block environment of the executor. + fn block_env(&self) -> BlockEnv; +} + +pub trait ExecutorExt { + /// Simulate the given transactions and return the results of each transaction. + fn simulate( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec; + + /// Get the fee estimation for the given transactions. + fn estimate_fee( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec>; + + /// Perform a contract entry point call and return the output. + fn call(&self, call: EntryPointCall) -> Result, ExecutionError>; +} diff --git a/crates/katana/executor/src/abstraction/mod.rs b/crates/katana/executor/src/abstraction/mod.rs new file mode 100644 index 0000000000..313ce8e045 --- /dev/null +++ b/crates/katana/executor/src/abstraction/mod.rs @@ -0,0 +1,186 @@ +mod error; +mod executor; + +pub use error::*; +pub use executor::*; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::receipt::Receipt; +use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; +use katana_primitives::transaction::TxWithHash; +use katana_primitives::FieldElement; +use katana_provider::traits::contract::ContractClassProvider; +use katana_provider::traits::state::StateProvider; +use katana_provider::ProviderResult; + +pub type ExecutorResult = Result; + +/// Transaction execution simulation flags. +/// +/// These flags can be used to control the behavior of the transaction execution, such as skipping +/// the transaction execution or validation, or ignoring the maximum fee when validating the +/// transaction. +#[derive(Debug, Clone, Default)] +pub struct SimulationFlag { + /// Skip the transaction execution. + pub skip_execute: bool, + /// Skip the transaction validation. + pub skip_validate: bool, + /// Skip checking nonce when validating the transaction. + pub skip_nonce_check: bool, + /// Skip the fee transfer after the transaction execution. + pub skip_fee_transfer: bool, + /// Ignore the maximum fee when validating the transaction. + pub ignore_max_fee: bool, +} + +impl SimulationFlag { + pub fn new() -> Self { + Self::default() + } + + /// Enables the skip execution flag. + pub fn skip_execute(mut self) -> Self { + self.skip_execute = true; + self + } + + /// Enables the skip validation flag. + pub fn skip_validate(mut self) -> Self { + self.skip_validate = true; + self + } + + /// Enables the skip nonce check flag. + pub fn skip_nonce_check(mut self) -> Self { + self.skip_nonce_check = true; + self + } + + /// Enables the skip fee transfer flag. + pub fn skip_fee_transfer(mut self) -> Self { + self.skip_fee_transfer = true; + self + } + + /// Enables the ignore max fee flag. + pub fn ignore_max_fee(mut self) -> Self { + self.ignore_max_fee = true; + self + } +} + +/// The output of a executor after a series of executions. +#[derive(Debug, Default)] +pub struct ExecutionOutput { + /// The state updates produced by the executions. + pub states: StateUpdatesWithDeclaredClasses, + /// The transactions that have been executed. + pub transactions: Vec<(TxWithHash, ExecutionResult)>, +} + +#[derive(Debug)] +pub struct EntryPointCall { + /// The address of the contract whose function you're calling. + pub contract_address: ContractAddress, + /// The input to the function. + pub calldata: Vec, + /// The contract function name. + pub entry_point_selector: FieldElement, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] +pub enum ExecutionResult { + Success { receipt: Receipt, trace: TxExecInfo, fee: TxFeeInfo }, + Failed { error: ExecutionError }, +} + +impl ExecutionResult { + pub fn new_success(receipt: Receipt, trace: TxExecInfo, fee: TxFeeInfo) -> Self { + ExecutionResult::Success { receipt, trace, fee } + } + + pub fn new_failed(error: impl Into) -> Self { + ExecutionResult::Failed { error: error.into() } + } + + pub fn is_success(&self) -> bool { + matches!(self, ExecutionResult::Success { .. }) + } + + pub fn is_failed(&self) -> bool { + !self.is_success() + } + + pub fn receipt(&self) -> Option<&Receipt> { + match self { + ExecutionResult::Success { receipt, .. } => Some(receipt), + _ => None, + } + } + + pub fn trace(&self) -> Option<&TxExecInfo> { + match self { + ExecutionResult::Success { trace, .. } => Some(trace), + _ => None, + } + } + + pub fn fee(&self) -> Option<&TxFeeInfo> { + match self { + ExecutionResult::Success { fee, .. } => Some(fee), + _ => None, + } + } +} + +#[derive(Debug, Clone)] +pub struct ResultAndStates { + pub result: ExecutionResult, + pub states: StateUpdates, +} + +/// A wrapper around a boxed [StateProvider] for implementing the executor's own state reader +/// traits. +pub(crate) struct StateProviderDb<'a>(pub(crate) Box); + +impl<'a> ContractClassProvider for StateProviderDb<'a> { + fn class(&self, hash: ClassHash) -> ProviderResult> { + self.0.class(hash) + } + + fn compiled_class_hash_of_class_hash( + &self, + hash: ClassHash, + ) -> ProviderResult> { + self.0.compiled_class_hash_of_class_hash(hash) + } + + fn sierra_class(&self, hash: ClassHash) -> ProviderResult> { + self.0.sierra_class(hash) + } +} + +impl<'a> StateProvider for StateProviderDb<'a> { + fn class_hash_of_contract( + &self, + address: ContractAddress, + ) -> ProviderResult> { + self.0.class_hash_of_contract(address) + } + + fn nonce(&self, address: ContractAddress) -> ProviderResult> { + self.0.nonce(address) + } + + fn storage( + &self, + address: ContractAddress, + storage_key: StorageKey, + ) -> ProviderResult> { + self.0.storage(address, storage_key) + } +} diff --git a/crates/katana/executor/src/blockifier/mod.rs b/crates/katana/executor/src/blockifier/mod.rs deleted file mode 100644 index 6da2ddc95c..0000000000 --- a/crates/katana/executor/src/blockifier/mod.rs +++ /dev/null @@ -1,232 +0,0 @@ -pub mod outcome; -pub mod state; -pub mod transactions; -pub mod utils; - -use std::sync::Arc; - -use blockifier::block_context::BlockContext; -use blockifier::transaction::errors::TransactionExecutionError; -use blockifier::transaction::objects::TransactionExecutionInfo; -use blockifier::transaction::transaction_execution::Transaction; -use blockifier::transaction::transactions::ExecutableTransaction; -use katana_primitives::env::{BlockEnv, CfgEnv}; -use katana_primitives::transaction::{ - DeclareTxWithClass, ExecutableTx, ExecutableTxWithHash, TxWithHash, -}; -use parking_lot::RwLock; -use tracing::{trace, warn}; - -use self::outcome::TxReceiptWithExecInfo; -use self::state::{CachedStateWrapper, StateRefDb}; -use self::transactions::BlockifierTx; -use self::utils::events_from_exec_info; -use crate::blockifier::utils::{ - pretty_print_resources, trace_events, warn_message_transaction_error_exec_error, -}; - -/// The result of a transaction execution. -type TxExecutionResult = Result; - -/// A transaction executor. -/// -/// The transactions will be executed in an iterator fashion, sequentially, in the -/// exact order they are provided to the executor. The execution is done within its -/// implementation of the [`Iterator`] trait. -pub struct TransactionExecutor<'a, T> { - /// A flag to enable/disable fee charging. - charge_fee: bool, - /// The block context the transactions will be executed on. - block_context: &'a BlockContext, - /// The transactions to be executed (in the exact order they are in the iterator). - transactions: T, - /// The state the transactions will be executed on. - state: &'a CachedStateWrapper, - /// A flag to enable/disable transaction validation. - validate: bool, - - // logs flags - error_log: bool, - events_log: bool, - resources_log: bool, -} - -impl<'a, T> TransactionExecutor<'a, T> -where - T: Iterator, -{ - pub fn new( - state: &'a CachedStateWrapper, - block_context: &'a BlockContext, - charge_fee: bool, - validate: bool, - transactions: T, - ) -> Self { - Self { - state, - charge_fee, - transactions, - block_context, - validate, - error_log: false, - events_log: false, - resources_log: false, - } - } - - pub fn with_events_log(self) -> Self { - Self { events_log: true, ..self } - } - - pub fn with_error_log(self) -> Self { - Self { error_log: true, ..self } - } - - pub fn with_resources_log(self) -> Self { - Self { resources_log: true, ..self } - } - - /// A method to conveniently execute all the transactions and return their results. - pub fn execute(self) -> Vec { - self.collect() - } -} - -impl<'a, T> Iterator for TransactionExecutor<'a, T> -where - T: Iterator, -{ - type Item = TxExecutionResult; - - fn next(&mut self) -> Option { - let res = self.transactions.next().map(|tx| { - execute_tx(tx, self.state, self.block_context, self.charge_fee, self.validate) - })?; - - match res { - Ok(ref info) => { - if self.error_log { - if let Some(err) = &info.revert_error { - let formatted_err = format!("{err:?}").replace("\\n", "\n"); - warn!(target: "executor", "Transaction execution error: {formatted_err}"); - } - } - - if self.resources_log { - trace!( - target: "executor", - "Transaction resource usage: {}", - pretty_print_resources(&info.actual_resources) - ); - } - - if self.events_log { - trace_events(&events_from_exec_info(info)); - } - - Some(res) - } - - Err(ref err) => { - if self.error_log { - warn_message_transaction_error_exec_error(err); - } - - Some(res) - } - } - } -} - -fn execute_tx( - tx: ExecutableTxWithHash, - state: &CachedStateWrapper, - block_context: &BlockContext, - charge_fee: bool, - validate: bool, -) -> TxExecutionResult { - let sierra = if let ExecutableTx::Declare(DeclareTxWithClass { - transaction, - sierra_class: Some(sierra_class), - .. - }) = tx.as_ref() - { - Some((transaction.class_hash(), sierra_class.clone())) - } else { - None - }; - - let res = match BlockifierTx::from(tx).0 { - Transaction::AccountTransaction(tx) => { - tx.execute(&mut state.inner(), block_context, charge_fee, validate) - } - Transaction::L1HandlerTransaction(tx) => { - tx.execute(&mut state.inner(), block_context, charge_fee, validate) - } - }; - - if res.is_ok() { - if let Some((class_hash, sierra_class)) = sierra { - state.sierra_class_mut().insert(class_hash, sierra_class); - } - } - - res -} - -pub type AcceptedTxPair = (TxWithHash, TxReceiptWithExecInfo); -pub type RejectedTxPair = (TxWithHash, TransactionExecutionError); - -pub struct PendingState { - /// The block context of the pending block. - pub block_envs: RwLock<(BlockEnv, CfgEnv)>, - /// The state of the pending block. - pub state: Arc, - /// The transactions that have been executed. - pub executed_txs: RwLock>, - /// The transactions that have been rejected. - pub rejected_txs: RwLock>, -} - -impl PendingState { - pub fn new(state: StateRefDb, block_env: BlockEnv, cfg_env: CfgEnv) -> Self { - Self { - block_envs: RwLock::new((block_env, cfg_env)), - state: Arc::new(CachedStateWrapper::new(state)), - executed_txs: RwLock::new(Vec::new()), - rejected_txs: RwLock::new(Vec::new()), - } - } - - pub fn reset_state(&self, state: StateRefDb, block_env: BlockEnv, cfg_env: CfgEnv) { - *self.block_envs.write() = (block_env, cfg_env); - self.state.reset_with_new_state(state); - } - - pub fn add_executed_txs(&self, transactions: Vec<(TxWithHash, TxExecutionResult)>) { - transactions.into_iter().for_each(|(tx, res)| self.add_executed_tx(tx, res)); - } - - /// Drain the pending transactions, returning the executed and rejected transactions. - pub fn take_txs_all(&self) -> (Vec, Vec) { - let executed_txs = std::mem::take(&mut *self.executed_txs.write()); - let rejected_txs = std::mem::take(&mut *self.rejected_txs.write()); - (executed_txs, rejected_txs) - } - - pub fn block_execution_envs(&self) -> (BlockEnv, CfgEnv) { - self.block_envs.read().clone() - } - - fn add_executed_tx(&self, tx: TxWithHash, execution_result: TxExecutionResult) { - match execution_result { - Ok(execution_info) => { - let receipt = TxReceiptWithExecInfo::new(&tx, execution_info); - self.executed_txs.write().push((tx, receipt)); - } - Err(err) => { - self.rejected_txs.write().push((tx, err)); - } - } - } -} diff --git a/crates/katana/executor/src/blockifier/outcome.rs b/crates/katana/executor/src/blockifier/outcome.rs deleted file mode 100644 index 72584dc7c9..0000000000 --- a/crates/katana/executor/src/blockifier/outcome.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::collections::HashMap; - -use blockifier::transaction::objects::TransactionExecutionInfo; -use katana_primitives::receipt::{ - DeclareTxReceipt, DeployAccountTxReceipt, InvokeTxReceipt, L1HandlerTxReceipt, Receipt, - TxExecutionResources, -}; -use katana_primitives::transaction::Tx; - -use super::utils::{events_from_exec_info, l2_to_l1_messages_from_exec_info}; - -#[derive(Clone)] -pub struct TxReceiptWithExecInfo { - pub receipt: Receipt, - pub execution_info: TransactionExecutionInfo, -} - -impl TxReceiptWithExecInfo { - pub fn new(tx: impl AsRef, execution_info: TransactionExecutionInfo) -> Self { - let actual_fee = execution_info.actual_fee.0; - - let events = events_from_exec_info(&execution_info); - let revert_error = execution_info.revert_error.clone(); - let messages_sent = l2_to_l1_messages_from_exec_info(&execution_info); - let actual_resources = parse_actual_resources(&execution_info.actual_resources.0); - - let receipt = match tx.as_ref() { - Tx::Invoke(_) => Receipt::Invoke(InvokeTxReceipt { - events, - actual_fee, - revert_error, - messages_sent, - execution_resources: actual_resources, - }), - - Tx::Declare(_) => Receipt::Declare(DeclareTxReceipt { - events, - actual_fee, - revert_error, - messages_sent, - execution_resources: actual_resources, - }), - - Tx::L1Handler(tx) => Receipt::L1Handler(L1HandlerTxReceipt { - events, - actual_fee, - revert_error, - messages_sent, - message_hash: tx.message_hash, - execution_resources: actual_resources, - }), - - Tx::DeployAccount(tx) => Receipt::DeployAccount(DeployAccountTxReceipt { - events, - actual_fee, - revert_error, - messages_sent, - execution_resources: actual_resources, - contract_address: tx.contract_address(), - }), - }; - - Self { receipt, execution_info } - } -} - -/// Parse the `actual resources` field from the execution info into a more structured type, -/// [`TxExecutionResources`]. -fn parse_actual_resources(resources: &HashMap) -> TxExecutionResources { - TxExecutionResources { - steps: resources.get("n_steps").copied().unwrap_or_default() as u64, - memory_holes: resources.get("memory_holes").map(|x| *x as u64), - ec_op_builtin: resources.get("ec_op_builtin").map(|x| *x as u64), - ecdsa_builtin: resources.get("ecdsa_builtin").map(|x| *x as u64), - keccak_builtin: resources.get("keccak_builtin").map(|x| *x as u64), - bitwise_builtin: resources.get("bitwise_builtin").map(|x| *x as u64), - pedersen_builtin: resources.get("pedersen_builtin").map(|x| *x as u64), - poseidon_builtin: resources.get("poseidon_builtin").map(|x| *x as u64), - range_check_builtin: resources.get("range_check_builtin").map(|x| *x as u64), - segment_arena_builtin: resources.get("segment_arena_builtin").map(|x| *x as u64), - } -} diff --git a/crates/katana/executor/src/blockifier/state.rs b/crates/katana/executor/src/blockifier/state.rs deleted file mode 100644 index 56f7afc18d..0000000000 --- a/crates/katana/executor/src/blockifier/state.rs +++ /dev/null @@ -1,245 +0,0 @@ -use std::collections::HashMap; - -use blockifier::state::cached_state::{CachedState, GlobalContractCache}; -use blockifier::state::errors::StateError; -use blockifier::state::state_api::StateReader; -use katana_primitives::contract::FlattenedSierraClass; -use katana_primitives::FieldElement; -use katana_provider::traits::contract::ContractClassProvider; -use katana_provider::traits::state::StateProvider; -use katana_provider::ProviderResult; -use parking_lot::{Mutex, RawMutex, RwLock}; -use starknet_api::core::{ClassHash, CompiledClassHash, Nonce, PatriciaKey}; -use starknet_api::hash::StarkHash; -use starknet_api::patricia_key; -use starknet_api::state::StorageKey; - -/// A state db only provide read access. -/// -/// This type implements the [`StateReader`] trait so that it can be used as a with [`CachedState`]. -pub struct StateRefDb(pub Box); - -impl StateRefDb { - pub fn new(provider: impl StateProvider + 'static) -> Self { - Self(Box::new(provider)) - } -} - -impl ContractClassProvider for StateRefDb { - fn class( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.class(hash) - } - - fn compiled_class_hash_of_class_hash( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.compiled_class_hash_of_class_hash(hash) - } - - fn sierra_class( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - self.0.sierra_class(hash) - } -} - -impl StateProvider for StateRefDb { - fn nonce( - &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - self.0.nonce(address) - } - - fn class_hash_of_contract( - &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - self.0.class_hash_of_contract(address) - } - - fn storage( - &self, - address: katana_primitives::contract::ContractAddress, - storage_key: katana_primitives::contract::StorageKey, - ) -> ProviderResult> { - self.0.storage(address, storage_key) - } -} - -impl StateReader for StateRefDb { - fn get_nonce_at( - &mut self, - contract_address: starknet_api::core::ContractAddress, - ) -> blockifier::state::state_api::StateResult { - StateProvider::nonce(&self.0, contract_address.into()) - .map(|n| Nonce(n.unwrap_or_default().into())) - .map_err(|e| StateError::StateReadError(e.to_string())) - } - - fn get_storage_at( - &mut self, - contract_address: starknet_api::core::ContractAddress, - key: starknet_api::state::StorageKey, - ) -> blockifier::state::state_api::StateResult { - StateProvider::storage(&self.0, contract_address.into(), (*key.0.key()).into()) - .map(|v| v.unwrap_or_default().into()) - .map_err(|e| StateError::StateReadError(e.to_string())) - } - - fn get_class_hash_at( - &mut self, - contract_address: starknet_api::core::ContractAddress, - ) -> blockifier::state::state_api::StateResult { - StateProvider::class_hash_of_contract(&self.0, contract_address.into()) - .map(|v| ClassHash(v.unwrap_or_default().into())) - .map_err(|e| StateError::StateReadError(e.to_string())) - } - - fn get_compiled_class_hash( - &mut self, - class_hash: starknet_api::core::ClassHash, - ) -> blockifier::state::state_api::StateResult { - if let Some(hash) = - ContractClassProvider::compiled_class_hash_of_class_hash(&self.0, class_hash.0.into()) - .map_err(|e| StateError::StateReadError(e.to_string()))? - { - Ok(CompiledClassHash(hash.into())) - } else { - Err(StateError::UndeclaredClassHash(class_hash)) - } - } - - fn get_compiled_contract_class( - &mut self, - class_hash: starknet_api::core::ClassHash, - ) -> blockifier::state::state_api::StateResult< - blockifier::execution::contract_class::ContractClass, - > { - if let Some(class) = ContractClassProvider::class(&self.0, class_hash.0.into()) - .map_err(|e| StateError::StateReadError(e.to_string()))? - { - Ok(class) - } else { - Err(StateError::UndeclaredClassHash(class_hash)) - } - } -} - -pub struct CachedStateWrapper { - inner: Mutex>, - sierra_class: RwLock>, -} - -impl CachedStateWrapper { - pub fn new(db: StateRefDb) -> Self { - Self { - sierra_class: Default::default(), - inner: Mutex::new(CachedState::new(db, GlobalContractCache::default())), - } - } - - pub(super) fn reset_with_new_state(&self, db: StateRefDb) { - *self.inner() = CachedState::new(db, GlobalContractCache::default()); - self.sierra_class_mut().clear(); - } - - pub fn inner( - &self, - ) -> parking_lot::lock_api::MutexGuard<'_, RawMutex, CachedState> { - self.inner.lock() - } - - pub fn sierra_class( - &self, - ) -> parking_lot::RwLockReadGuard< - '_, - HashMap, - > { - self.sierra_class.read() - } - - pub fn sierra_class_mut( - &self, - ) -> parking_lot::RwLockWriteGuard< - '_, - HashMap, - > { - self.sierra_class.write() - } -} - -impl ContractClassProvider for CachedStateWrapper { - fn class( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - let Ok(class) = self.inner().get_compiled_contract_class(ClassHash(hash.into())) else { - return Ok(None); - }; - Ok(Some(class)) - } - - fn compiled_class_hash_of_class_hash( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - let Ok(hash) = self.inner().get_compiled_class_hash(ClassHash(hash.into())) else { - return Ok(None); - }; - Ok(Some(hash.0.into())) - } - - fn sierra_class( - &self, - hash: katana_primitives::contract::ClassHash, - ) -> ProviderResult> { - if let Some(class) = self.sierra_class().get(&hash) { - Ok(Some(class.clone())) - } else { - self.inner.lock().state.0.sierra_class(hash) - } - } -} - -impl StateProvider for CachedStateWrapper { - fn storage( - &self, - address: katana_primitives::contract::ContractAddress, - storage_key: katana_primitives::contract::StorageKey, - ) -> ProviderResult> { - let Ok(value) = - self.inner().get_storage_at(address.into(), StorageKey(patricia_key!(storage_key))) - else { - return Ok(None); - }; - Ok(Some(value.into())) - } - - fn nonce( - &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - let Ok(nonce) = self.inner().get_nonce_at(address.into()) else { - return Ok(None); - }; - Ok(Some(nonce.0.into())) - } - - fn class_hash_of_contract( - &self, - address: katana_primitives::contract::ContractAddress, - ) -> ProviderResult> { - let Ok(hash) = self.inner().get_class_hash_at(address.into()) else { - return Ok(None); - }; - - let hash = hash.0.into(); - if hash == FieldElement::ZERO { Ok(None) } else { Ok(Some(hash)) } - } -} diff --git a/crates/katana/executor/src/blockifier/transactions.rs b/crates/katana/executor/src/blockifier/transactions.rs deleted file mode 100644 index 4560a4d2d5..0000000000 --- a/crates/katana/executor/src/blockifier/transactions.rs +++ /dev/null @@ -1,241 +0,0 @@ -use std::collections::BTreeMap; -use std::sync::Arc; - -use ::blockifier::transaction::transaction_execution::Transaction; -use ::blockifier::transaction::transactions::{DeployAccountTransaction, InvokeTransaction}; -use blockifier::transaction::account_transaction::AccountTransaction; -use blockifier::transaction::transactions::{DeclareTransaction, L1HandlerTransaction}; -use katana_primitives::transaction::{ - DeclareTx, DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, -}; -use starknet_api::core::{ClassHash, CompiledClassHash, EntryPointSelector, Nonce}; -use starknet_api::data_availability::DataAvailabilityMode; -use starknet_api::transaction::{ - AccountDeploymentData, Calldata, ContractAddressSalt, - DeclareTransaction as ApiDeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, - DeclareTransactionV3, DeployAccountTransaction as ApiDeployAccountTransaction, - DeployAccountTransactionV1, DeployAccountTransactionV3, Fee, - InvokeTransaction as ApiInvokeTransaction, PaymasterData, Resource, ResourceBounds, - ResourceBoundsMapping, Tip, TransactionHash, TransactionSignature, TransactionVersion, -}; - -/// A newtype wrapper for execution transaction used in `blockifier`. -pub struct BlockifierTx(pub(super) ::blockifier::transaction::transaction_execution::Transaction); - -impl From for BlockifierTx { - fn from(value: ExecutableTxWithHash) -> Self { - let hash = value.hash; - - let tx = match value.transaction { - ExecutableTx::Invoke(tx) => match tx { - InvokeTx::V1(tx) => { - let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - - Transaction::AccountTransaction(AccountTransaction::Invoke(InvokeTransaction { - tx: ApiInvokeTransaction::V1( - starknet_api::transaction::InvokeTransactionV1 { - max_fee: Fee(tx.max_fee), - nonce: Nonce(tx.nonce.into()), - sender_address: tx.sender_address.into(), - signature: TransactionSignature(signature), - calldata: Calldata(Arc::new(calldata)), - }, - ), - tx_hash: TransactionHash(hash.into()), - only_query: false, - })) - } - - InvokeTx::V3(tx) => { - let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - - let paymaster_data = tx.paymaster_data.into_iter().map(|f| f.into()).collect(); - let account_deploy_data = - tx.account_deployment_data.into_iter().map(|f| f.into()).collect(); - let fee_data_availability_mode = to_api_da_mode(tx.fee_data_availability_mode); - let nonce_data_availability_mode = - to_api_da_mode(tx.nonce_data_availability_mode); - - Transaction::AccountTransaction(AccountTransaction::Invoke(InvokeTransaction { - tx: ApiInvokeTransaction::V3( - starknet_api::transaction::InvokeTransactionV3 { - tip: Tip(tx.tip), - nonce: Nonce(tx.nonce.into()), - sender_address: tx.sender_address.into(), - signature: TransactionSignature(signature), - calldata: Calldata(Arc::new(calldata)), - paymaster_data: PaymasterData(paymaster_data), - account_deployment_data: AccountDeploymentData(account_deploy_data), - fee_data_availability_mode, - nonce_data_availability_mode, - resource_bounds: to_api_resource_bounds(tx.resource_bounds), - }, - ), - tx_hash: TransactionHash(hash.into()), - only_query: false, - })) - } - }, - - ExecutableTx::DeployAccount(tx) => match tx { - DeployAccountTx::V1(tx) => { - let calldata = tx.constructor_calldata.into_iter().map(|f| f.into()).collect(); - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - let salt = ContractAddressSalt(tx.contract_address_salt.into()); - - Transaction::AccountTransaction(AccountTransaction::DeployAccount( - DeployAccountTransaction { - contract_address: tx.contract_address.into(), - tx: ApiDeployAccountTransaction::V1(DeployAccountTransactionV1 { - max_fee: Fee(tx.max_fee), - nonce: Nonce(tx.nonce.into()), - signature: TransactionSignature(signature), - class_hash: ClassHash(tx.class_hash.into()), - constructor_calldata: Calldata(Arc::new(calldata)), - contract_address_salt: salt, - }), - tx_hash: TransactionHash(hash.into()), - only_query: false, - }, - )) - } - - DeployAccountTx::V3(tx) => { - let calldata = tx.constructor_calldata.into_iter().map(|f| f.into()).collect(); - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - let salt = ContractAddressSalt(tx.contract_address_salt.into()); - - let paymaster_data = tx.paymaster_data.into_iter().map(|f| f.into()).collect(); - let fee_data_availability_mode = to_api_da_mode(tx.fee_data_availability_mode); - let nonce_data_availability_mode = - to_api_da_mode(tx.nonce_data_availability_mode); - - Transaction::AccountTransaction(AccountTransaction::DeployAccount( - DeployAccountTransaction { - contract_address: tx.contract_address.into(), - tx: ApiDeployAccountTransaction::V3(DeployAccountTransactionV3 { - tip: Tip(tx.tip), - nonce: Nonce(tx.nonce.into()), - signature: TransactionSignature(signature), - class_hash: ClassHash(tx.class_hash.into()), - constructor_calldata: Calldata(Arc::new(calldata)), - contract_address_salt: salt, - paymaster_data: PaymasterData(paymaster_data), - fee_data_availability_mode, - nonce_data_availability_mode, - resource_bounds: to_api_resource_bounds(tx.resource_bounds), - }), - tx_hash: TransactionHash(hash.into()), - only_query: false, - }, - )) - } - }, - - ExecutableTx::Declare(tx) => { - let contract_class = tx.compiled_class; - - let tx = match tx.transaction { - DeclareTx::V1(tx) => { - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - - ApiDeclareTransaction::V1(DeclareTransactionV0V1 { - max_fee: Fee(tx.max_fee), - nonce: Nonce(tx.nonce.into()), - sender_address: tx.sender_address.into(), - signature: TransactionSignature(signature), - class_hash: ClassHash(tx.class_hash.into()), - }) - } - - DeclareTx::V2(tx) => { - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - - ApiDeclareTransaction::V2(DeclareTransactionV2 { - max_fee: Fee(tx.max_fee), - nonce: Nonce(tx.nonce.into()), - sender_address: tx.sender_address.into(), - signature: TransactionSignature(signature), - class_hash: ClassHash(tx.class_hash.into()), - compiled_class_hash: CompiledClassHash(tx.compiled_class_hash.into()), - }) - } - - DeclareTx::V3(tx) => { - let signature = tx.signature.into_iter().map(|f| f.into()).collect(); - - let paymaster_data = - tx.paymaster_data.into_iter().map(|f| f.into()).collect(); - let fee_data_availability_mode = - to_api_da_mode(tx.fee_data_availability_mode); - let nonce_data_availability_mode = - to_api_da_mode(tx.nonce_data_availability_mode); - let account_deploy_data = - tx.account_deployment_data.into_iter().map(|f| f.into()).collect(); - - ApiDeclareTransaction::V3(DeclareTransactionV3 { - tip: Tip(tx.tip), - nonce: Nonce(tx.nonce.into()), - sender_address: tx.sender_address.into(), - signature: TransactionSignature(signature), - class_hash: ClassHash(tx.class_hash.into()), - account_deployment_data: AccountDeploymentData(account_deploy_data), - compiled_class_hash: CompiledClassHash(tx.compiled_class_hash.into()), - paymaster_data: PaymasterData(paymaster_data), - fee_data_availability_mode, - nonce_data_availability_mode, - resource_bounds: to_api_resource_bounds(tx.resource_bounds), - }) - } - }; - - let tx = DeclareTransaction::new(tx, TransactionHash(hash.into()), contract_class) - .expect("class mismatch"); - Transaction::AccountTransaction(AccountTransaction::Declare(tx)) - } - - ExecutableTx::L1Handler(tx) => { - let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); - - Transaction::L1HandlerTransaction(L1HandlerTransaction { - paid_fee_on_l1: Fee(tx.paid_fee_on_l1), - tx: starknet_api::transaction::L1HandlerTransaction { - nonce: Nonce(tx.nonce.into()), - calldata: Calldata(Arc::new(calldata)), - version: TransactionVersion(1u128.into()), - contract_address: tx.contract_address.into(), - entry_point_selector: EntryPointSelector(tx.entry_point_selector.into()), - }, - tx_hash: TransactionHash(hash.into()), - }) - } - }; - - Self(tx) - } -} - -fn to_api_da_mode(mode: starknet::core::types::DataAvailabilityMode) -> DataAvailabilityMode { - match mode { - starknet::core::types::DataAvailabilityMode::L1 => DataAvailabilityMode::L1, - starknet::core::types::DataAvailabilityMode::L2 => DataAvailabilityMode::L2, - } -} - -fn to_api_resource_bounds( - resource_bounds: starknet::core::types::ResourceBoundsMapping, -) -> ResourceBoundsMapping { - let l1_gas = ResourceBounds { - max_amount: resource_bounds.l1_gas.max_amount, - max_price_per_unit: resource_bounds.l1_gas.max_price_per_unit, - }; - - let l2_gas = ResourceBounds { - max_amount: resource_bounds.l2_gas.max_amount, - max_price_per_unit: resource_bounds.l2_gas.max_price_per_unit, - }; - - ResourceBoundsMapping(BTreeMap::from([(Resource::L1Gas, l1_gas), (Resource::L2Gas, l2_gas)])) -} diff --git a/crates/katana/executor/src/blockifier/utils.rs b/crates/katana/executor/src/blockifier/utils.rs deleted file mode 100644 index c52ef32a5b..0000000000 --- a/crates/katana/executor/src/blockifier/utils.rs +++ /dev/null @@ -1,562 +0,0 @@ -use std::collections::HashMap; -use std::sync::Arc; - -use ::blockifier::block_context::BlockContext; -use ::blockifier::execution::call_info::CallInfo; -use ::blockifier::execution::common_hints::ExecutionMode; -use ::blockifier::execution::entry_point::{ - CallEntryPoint, EntryPointExecutionContext, ExecutionResources, -}; -use ::blockifier::execution::errors::EntryPointExecutionError; -use ::blockifier::state::cached_state::{CachedState, GlobalContractCache, MutRefState}; -use ::blockifier::transaction::objects::AccountTransactionContext; -use blockifier::block_context::{BlockInfo, ChainInfo, FeeTokenAddresses, GasPrices}; -use blockifier::fee::fee_utils::{calculate_l1_gas_by_vm_usage, extract_l1_gas_and_vm_usage}; -use blockifier::state::state_api::State; -use blockifier::transaction::errors::TransactionExecutionError; -use blockifier::transaction::objects::{ - DeprecatedAccountTransactionContext, ResourcesMapping, TransactionExecutionInfo, -}; -use cairo_vm::vm::runners::builtin_runner::{ - BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, - POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, SEGMENT_ARENA_BUILTIN_NAME, - SIGNATURE_BUILTIN_NAME, -}; -use convert_case::{Case, Casing}; -use katana_primitives::contract::ContractAddress; -use katana_primitives::env::{BlockEnv, CfgEnv}; -use katana_primitives::receipt::{Event, MessageToL1}; -use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; -use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash}; -use katana_primitives::FieldElement; -use katana_provider::traits::contract::ContractClassProvider; -use katana_provider::traits::state::StateProvider; -use starknet::core::types::{ - DeclareTransactionTrace, DeployAccountTransactionTrace, ExecuteInvocation, FeeEstimate, - FunctionInvocation, InvokeTransactionTrace, L1HandlerTransactionTrace, PriceUnit, - RevertedInvocation, SimulatedTransaction, TransactionTrace, -}; -use starknet::core::utils::parse_cairo_short_string; -use starknet::macros::felt; -use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::EntryPointSelector; -use starknet_api::hash::StarkFelt; -use starknet_api::transaction::Calldata; -use tracing::trace; - -use super::state::{CachedStateWrapper, StateRefDb}; -use super::TransactionExecutor; - -#[derive(Debug)] -pub struct EntryPointCall { - /// The address of the contract whose function you're calling. - pub contract_address: ContractAddress, - /// The input to the function. - pub calldata: Vec, - /// The function selector. - pub entry_point_selector: FieldElement, -} - -/// Perform a function call on a contract and retrieve the return values. -pub fn call( - request: EntryPointCall, - block_context: BlockContext, - state: Box, -) -> Result, TransactionExecutionError> { - let res = raw_call(request, block_context, state, 1_000_000_000)?; - let retdata = res.execution.retdata.0; - let retdata = retdata.into_iter().map(|f| f.into()).collect::>(); - Ok(retdata) -} - -/// Estimate the execution fee for a list of transactions. -pub fn estimate_fee( - transactions: impl Iterator, - block_context: BlockContext, - state: Box, - validate: bool, -) -> Result, TransactionExecutionError> { - let state = CachedStateWrapper::new(StateRefDb(state)); - let results = TransactionExecutor::new(&state, &block_context, true, validate, transactions) - .with_error_log() - .execute(); - - results - .into_iter() - .map(|res| { - let exec_info = res?; - - if exec_info.revert_error.is_some() { - return Err(TransactionExecutionError::ExecutionError( - EntryPointExecutionError::ExecutionFailed { error_data: Default::default() }, - )); - } - - calculate_execution_fee(&block_context, &exec_info) - }) - .collect::, _>>() -} - -/// Simulate a transaction's execution on the state -pub fn simulate_transactions( - transactions: Vec, - block_context: &BlockContext, - state: Box, - validate: bool, - charge_fee: bool, -) -> Result, TransactionExecutionError> { - let state = CachedStateWrapper::new(StateRefDb(state)); - let results = TransactionExecutor::new( - &state, - block_context, - charge_fee, - validate, - transactions.clone().into_iter(), - ) - .with_error_log() - .execute(); - - results - .into_iter() - .zip(transactions) - .map(|(result, tx)| { - let result = result?; - let function_invocation = result - .execute_call_info - .as_ref() - .map(function_invocation_from_call_info) - .ok_or(TransactionExecutionError::ExecutionError( - EntryPointExecutionError::ExecutionFailed { error_data: Default::default() }, - )); - - let validate_invocation = - result.validate_call_info.as_ref().map(function_invocation_from_call_info); - - let fee_transfer_invocation = - result.fee_transfer_call_info.as_ref().map(function_invocation_from_call_info); - - let transaction_trace = match &tx.transaction { - ExecutableTx::Declare(_) => TransactionTrace::Declare(DeclareTransactionTrace { - validate_invocation, - fee_transfer_invocation, - state_diff: None, - }), - ExecutableTx::DeployAccount(_) => { - TransactionTrace::DeployAccount(DeployAccountTransactionTrace { - constructor_invocation: function_invocation?, - validate_invocation, - fee_transfer_invocation, - state_diff: None, - }) - } - ExecutableTx::Invoke(_) => TransactionTrace::Invoke(InvokeTransactionTrace { - validate_invocation, - execute_invocation: if let Some(revert_reason) = result.revert_error.as_ref() { - ExecuteInvocation::Reverted(RevertedInvocation { - revert_reason: revert_reason.clone(), - }) - } else { - ExecuteInvocation::Success(function_invocation?) - }, - fee_transfer_invocation, - state_diff: None, - }), - ExecutableTx::L1Handler(_) => { - TransactionTrace::L1Handler(L1HandlerTransactionTrace { - function_invocation: function_invocation?, - state_diff: None, - }) - } - }; - let fee_estimation = calculate_execution_fee(block_context, &result)?; - - Ok(SimulatedTransaction { transaction_trace, fee_estimation }) - }) - .collect::, _>>() -} - -/// Perform a raw entrypoint call of a contract. -pub fn raw_call( - request: EntryPointCall, - block_context: BlockContext, - state: Box, - initial_gas: u64, -) -> Result { - let mut state = CachedState::new(StateRefDb(state), GlobalContractCache::default()); - let mut state = CachedState::new(MutRefState::new(&mut state), GlobalContractCache::default()); - - let call = CallEntryPoint { - initial_gas, - storage_address: request.contract_address.into(), - entry_point_selector: EntryPointSelector(request.entry_point_selector.into()), - calldata: Calldata(Arc::new(request.calldata.into_iter().map(|f| f.into()).collect())), - ..Default::default() - }; - - // TODO: this must be false if fees are disabled I assume. - let limit_steps_by_resources = true; - - // Now, the max step is not given directly to this function. - // It's computed by a new function max_steps, and it tooks the values - // from teh block context itself instead of the input give. - // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/execution/entry_point.rs#L165 - // The blockifier patch must be adjusted to modify this function to return - // the limit we have into the block context without min applied: - // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/execution/entry_point.rs#L215 - call.execute( - &mut state, - &mut ExecutionResources::default(), - &mut EntryPointExecutionContext::new( - &block_context, - // TODO: the current does not have Default, let's use the old one for now. - &AccountTransactionContext::Deprecated(DeprecatedAccountTransactionContext::default()), - ExecutionMode::Execute, - limit_steps_by_resources, - )?, - ) - .map_err(TransactionExecutionError::ExecutionError) -} - -/// Calculate the fee of a transaction execution. -pub fn calculate_execution_fee( - block_context: &BlockContext, - exec_info: &TransactionExecutionInfo, -) -> Result { - let (l1_gas_usage, vm_resources) = extract_l1_gas_and_vm_usage(&exec_info.actual_resources); - let l1_gas_by_vm_usage = calculate_l1_gas_by_vm_usage(block_context, &vm_resources)?; - - let total_l1_gas_usage = l1_gas_usage as f64 + l1_gas_by_vm_usage; - - // Gas prices are now in two currencies: eth and strk. - // For now let's only consider eth to be compatible with V2. - // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/block_context.rs#L19C26-L19C26 - // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/block_context.rs#L49 - let gas_price = block_context.block_info.gas_prices.eth_l1_gas_price as u64; - let gas_consumed = total_l1_gas_usage.ceil() as u64; - let overall_fee = total_l1_gas_usage.ceil() as u64 * gas_price; - - Ok(FeeEstimate { - gas_price: gas_price.into(), - gas_consumed: gas_consumed.into(), - overall_fee: overall_fee.into(), - unit: PriceUnit::Wei, - }) -} - -/// Create a block context from the chain environment values. -pub fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { - let fee_token_addresses = FeeTokenAddresses { - eth_fee_token_address: cfg_env.fee_token_addresses.eth.into(), - strk_fee_token_address: ContractAddress(felt!("0xb00b5")).into(), - }; - - let gas_prices = GasPrices { - eth_l1_gas_price: block_env.l1_gas_prices.eth, - strk_l1_gas_price: block_env.l1_gas_prices.strk, - eth_l1_data_gas_price: 0, - strk_l1_data_gas_price: 0, - }; - - BlockContext { - block_info: BlockInfo { - gas_prices, - block_number: BlockNumber(block_env.number), - block_timestamp: BlockTimestamp(block_env.timestamp), - sequencer_address: block_env.sequencer_address.into(), - vm_resource_fee_cost: cfg_env.vm_resource_fee_cost.clone().into(), - validate_max_n_steps: cfg_env.validate_max_n_steps, - invoke_tx_max_n_steps: cfg_env.invoke_tx_max_n_steps, - max_recursion_depth: cfg_env.max_recursion_depth, - use_kzg_da: false, - }, - chain_info: ChainInfo { fee_token_addresses, chain_id: cfg_env.chain_id.into() }, - } -} - -pub(crate) fn warn_message_transaction_error_exec_error(err: &TransactionExecutionError) { - match err { - TransactionExecutionError::ExecutionError(ref eperr) => match eperr { - EntryPointExecutionError::ExecutionFailed { error_data } => { - let mut reasons: Vec = vec![]; - error_data.iter().for_each(|felt| { - if let Ok(s) = parse_cairo_short_string(&FieldElement::from(*felt)) { - reasons.push(s); - } - }); - - tracing::warn!(target: "executor", - "Transaction validation error: {}", reasons.join(" ")); - } - _ => tracing::warn!(target: "executor", - "Transaction validation error: {:?}", err), - }, - _ => tracing::warn!(target: "executor", - "Transaction validation error: {:?}", err), - } -} - -pub(crate) fn pretty_print_resources(resources: &ResourcesMapping) -> String { - let mut mapped_strings: Vec<_> = resources - .0 - .iter() - .filter_map(|(k, v)| match k.as_str() { - "l1_gas_usage" => Some(format!("L1 Gas: {}", v)), - "range_check_builtin" => Some(format!("Range Checks: {}", v)), - "ecdsa_builtin" => Some(format!("ECDSA: {}", v)), - "n_steps" => None, - "pedersen_builtin" => Some(format!("Pedersen: {}", v)), - "bitwise_builtin" => Some(format!("Bitwise: {}", v)), - "keccak_builtin" => Some(format!("Keccak: {}", v)), - _ => Some(format!("{}: {}", k.to_case(Case::Title), v)), - }) - .collect::>(); - - // Sort the strings alphabetically - mapped_strings.sort(); - - // Prepend "Steps" if it exists, so it is always first - if let Some(steps) = resources.0.get("n_steps") { - mapped_strings.insert(0, format!("Steps: {}", steps)); - } - - mapped_strings.join(" | ") -} - -pub fn get_state_update_from_cached_state( - state: &CachedStateWrapper, -) -> StateUpdatesWithDeclaredClasses { - let state_diff = state.inner().to_state_diff(); - - let declared_sierra_classes = state.sierra_class().clone(); - - let declared_compiled_classes = state_diff - .class_hash_to_compiled_class_hash - .iter() - .map(|(class_hash, _)| { - let class = state.class(class_hash.0.into()).unwrap().expect("must exist if declared"); - (class_hash.0.into(), class) - }) - .collect::>(); - - let nonce_updates = - state_diff - .address_to_nonce - .into_iter() - .map(|(key, value)| (key.into(), value.0.into())) - .collect::>(); - - let storage_changes = state_diff - .storage_updates - .into_iter() - .map(|(addr, entries)| { - let entries = entries - .into_iter() - .map(|(k, v)| ((*k.0.key()).into(), v.into())) - .collect::>(); - - (addr.into(), entries) - }) - .collect::>(); - - let contract_updates = state_diff - .address_to_class_hash - .into_iter() - .map(|(key, value)| (key.into(), value.0.into())) - .collect::>(); - - let declared_classes = state_diff - .class_hash_to_compiled_class_hash - .into_iter() - .map(|(key, value)| (key.0.into(), value.0.into())) - .collect::>(); - - StateUpdatesWithDeclaredClasses { - declared_sierra_classes, - declared_compiled_classes, - state_updates: StateUpdates { - nonce_updates, - storage_updates: storage_changes, - contract_updates, - declared_classes, - }, - } -} - -pub(super) fn trace_events(events: &[Event]) { - for e in events { - let formatted_keys = - e.keys.iter().map(|k| format!("{k:#x}")).collect::>().join(", "); - - trace!(target: "executor", "Event emitted keys=[{}]", formatted_keys); - } -} - -pub(super) fn events_from_exec_info(execution_info: &TransactionExecutionInfo) -> Vec { - let mut events: Vec = vec![]; - - fn get_events_recursively(call_info: &CallInfo) -> Vec { - let mut events: Vec = vec![]; - - events.extend(call_info.execution.events.iter().map(|e| Event { - from_address: call_info.call.storage_address.into(), - data: e.event.data.0.iter().map(|d| (*d).into()).collect(), - keys: e.event.keys.iter().map(|k| k.0.into()).collect(), - })); - - call_info.inner_calls.iter().for_each(|call| { - events.extend(get_events_recursively(call)); - }); - - events - } - - if let Some(ref call) = execution_info.validate_call_info { - events.extend(get_events_recursively(call)); - } - - if let Some(ref call) = execution_info.execute_call_info { - events.extend(get_events_recursively(call)); - } - - if let Some(ref call) = execution_info.fee_transfer_call_info { - events.extend(get_events_recursively(call)); - } - - events -} - -pub(super) fn l2_to_l1_messages_from_exec_info( - execution_info: &TransactionExecutionInfo, -) -> Vec { - let mut messages = vec![]; - - fn get_messages_recursively(info: &CallInfo) -> Vec { - let mut messages = vec![]; - - // By default, `from_address` must correspond to the contract address that - // is sending the message. In the case of library calls, `code_address` is `None`, - // we then use the `caller_address` instead (which can also be an account). - let from_address = if let Some(code_address) = info.call.code_address { - *code_address.0.key() - } else { - *info.call.caller_address.0.key() - }; - - messages.extend(info.execution.l2_to_l1_messages.iter().map(|m| MessageToL1 { - to_address: - FieldElement::from_byte_slice_be(m.message.to_address.0.as_bytes()).unwrap(), - from_address: ContractAddress(from_address.into()), - payload: m.message.payload.0.iter().map(|p| (*p).into()).collect(), - })); - - info.inner_calls.iter().for_each(|call| { - messages.extend(get_messages_recursively(call)); - }); - - messages - } - - if let Some(ref info) = execution_info.validate_call_info { - messages.extend(get_messages_recursively(info)); - } - - if let Some(ref info) = execution_info.execute_call_info { - messages.extend(get_messages_recursively(info)); - } - - if let Some(ref info) = execution_info.fee_transfer_call_info { - messages.extend(get_messages_recursively(info)); - } - - messages -} - -fn function_invocation_from_call_info(info: &CallInfo) -> FunctionInvocation { - let entry_point_type = match info.call.entry_point_type { - starknet_api::deprecated_contract_class::EntryPointType::Constructor => { - starknet::core::types::EntryPointType::Constructor - } - starknet_api::deprecated_contract_class::EntryPointType::External => { - starknet::core::types::EntryPointType::External - } - starknet_api::deprecated_contract_class::EntryPointType::L1Handler => { - starknet::core::types::EntryPointType::L1Handler - } - }; - let call_type = match info.call.call_type { - blockifier::execution::entry_point::CallType::Call => starknet::core::types::CallType::Call, - blockifier::execution::entry_point::CallType::Delegate => { - starknet::core::types::CallType::Delegate - } - }; - - let calls = info.inner_calls.iter().map(function_invocation_from_call_info).collect(); - let events = info - .execution - .events - .iter() - .map(|e| starknet::core::types::OrderedEvent { - order: e.order as u64, - data: e.event.data.0.iter().map(|d| (*d).into()).collect(), - keys: e.event.keys.iter().map(|k| k.0.into()).collect(), - }) - .collect(); - let messages = info - .execution - .l2_to_l1_messages - .iter() - .map(|m| starknet::core::types::OrderedMessage { - order: m.order as u64, - to_address: (Into::::into(m.message.to_address)).into(), - from_address: (*info.call.storage_address.0.key()).into(), - payload: m.message.payload.0.iter().map(|p| (*p).into()).collect(), - }) - .collect(); - - let vm_resources = info.vm_resources.filter_unused_builtins(); - let get_vm_resource = - |name: &str| vm_resources.builtin_instance_counter.get(name).map(|r| *r as u64); - let execution_resources = starknet::core::types::ExecutionResources { - steps: vm_resources.n_steps as u64, - memory_holes: Some(vm_resources.n_memory_holes as u64), - range_check_builtin_applications: get_vm_resource(RANGE_CHECK_BUILTIN_NAME), - pedersen_builtin_applications: get_vm_resource(HASH_BUILTIN_NAME), - poseidon_builtin_applications: get_vm_resource(POSEIDON_BUILTIN_NAME), - ec_op_builtin_applications: get_vm_resource(EC_OP_BUILTIN_NAME), - ecdsa_builtin_applications: get_vm_resource(SIGNATURE_BUILTIN_NAME), - bitwise_builtin_applications: get_vm_resource(BITWISE_BUILTIN_NAME), - keccak_builtin_applications: get_vm_resource(KECCAK_BUILTIN_NAME), - segment_arena_builtin: get_vm_resource(SEGMENT_ARENA_BUILTIN_NAME), - }; - - FunctionInvocation { - contract_address: (*info.call.storage_address.0.key()).into(), - entry_point_selector: info.call.entry_point_selector.0.into(), - calldata: info.call.calldata.0.iter().map(|f| (*f).into()).collect(), - caller_address: (*info.call.caller_address.0.key()).into(), - // See - class_hash: info.call.class_hash.expect("Class hash mut be set after execution").0.into(), - entry_point_type, - call_type, - result: info.execution.retdata.0.iter().map(|f| (*f).into()).collect(), - calls, - events, - messages, - execution_resources, - } -} diff --git a/crates/katana/executor/src/implementation/blockifier/error.rs b/crates/katana/executor/src/implementation/blockifier/error.rs new file mode 100644 index 0000000000..d920d3bded --- /dev/null +++ b/crates/katana/executor/src/implementation/blockifier/error.rs @@ -0,0 +1,103 @@ +use blockifier::execution::errors::{EntryPointExecutionError, PreExecutionError}; +use blockifier::execution::execution_utils::format_panic_data; +use blockifier::state::errors::StateError; +use blockifier::transaction::errors::{ + TransactionExecutionError, TransactionFeeError, TransactionPreValidationError, +}; + +use crate::implementation::blockifier::utils::to_address; +use crate::ExecutionError; + +impl From for ExecutionError { + fn from(error: TransactionExecutionError) -> Self { + match error { + TransactionExecutionError::DeclareTransactionError { class_hash } => { + Self::ClassAlreadyDeclared(class_hash.0.into()) + } + TransactionExecutionError::ValidateTransactionError(e) => { + Self::TransactionValidationFailed(Box::new(Self::from(e))) + } + TransactionExecutionError::StateError(e) => Self::from(e), + TransactionExecutionError::TransactionPreValidationError(e) => Self::from(e), + TransactionExecutionError::TransactionFeeError(e) => Self::from(e), + TransactionExecutionError::ExecutionError(e) => Self::from(e), + TransactionExecutionError::ContractConstructorExecutionFailed(e) => { + Self::ConstructorExecutionFailed(Box::new(Self::from(e))) + } + e => Self::Other(e.to_string()), + } + } +} + +impl From for ExecutionError { + fn from(error: EntryPointExecutionError) -> Self { + match error { + EntryPointExecutionError::ExecutionFailed { error_data } => { + Self::ExecutionFailed { reason: format_panic_data(&error_data) } + } + EntryPointExecutionError::InvalidExecutionInput { input_descriptor, info } => { + Self::InvalidInput { input_descriptor, info } + } + EntryPointExecutionError::RecursionDepthExceeded => Self::RecursionDepthExceeded, + EntryPointExecutionError::StateError(e) => Self::from(e), + EntryPointExecutionError::PreExecutionError(e) => Self::from(e), + e => Self::Other(e.to_string()), + } + } +} + +impl From for ExecutionError { + fn from(error: PreExecutionError) -> Self { + match error { + PreExecutionError::EntryPointNotFound(selector) => { + Self::EntryPointNotFound(selector.0.into()) + } + PreExecutionError::UninitializedStorageAddress(address) => { + Self::ContractNotDeployed(to_address(address)) + } + PreExecutionError::StateError(e) => Self::from(e), + e => Self::Other(e.to_string()), + } + } +} + +impl From for ExecutionError { + fn from(error: TransactionPreValidationError) -> Self { + match error { + TransactionPreValidationError::InvalidNonce { + account_nonce, + incoming_tx_nonce, + .. + } => Self::InvalidNonce { + actual: account_nonce.0.into(), + expected: incoming_tx_nonce.0.into(), + }, + TransactionPreValidationError::TransactionFeeError(e) => Self::from(e), + TransactionPreValidationError::StateError(e) => Self::from(e), + } + } +} + +impl From for ExecutionError { + fn from(error: TransactionFeeError) -> Self { + match error { + TransactionFeeError::ExecuteFeeTransferError(e) => { + Self::FeeTransferError(e.to_string()) + } + TransactionFeeError::MaxFeeTooLow { min_fee, max_fee } => { + Self::MaxFeeTooLow { min: min_fee.0, max_fee: max_fee.0 } + } + TransactionFeeError::StateError(e) => Self::from(e), + e => Self::Other(e.to_string()), + } + } +} + +impl From for ExecutionError { + fn from(error: StateError) -> Self { + match error { + StateError::UndeclaredClassHash(hash) => Self::UndeclaredClass(hash.0.into()), + e => Self::Other(e.to_string()), + } + } +} diff --git a/crates/katana/executor/src/implementation/blockifier/mod.rs b/crates/katana/executor/src/implementation/blockifier/mod.rs new file mode 100644 index 0000000000..9d9a690b22 --- /dev/null +++ b/crates/katana/executor/src/implementation/blockifier/mod.rs @@ -0,0 +1,261 @@ +mod error; +mod output; +mod state; +mod utils; + +use blockifier::block_context::BlockContext; +use blockifier::state::cached_state::{self, MutRefState}; +use blockifier::state::state_api::StateReader; +use blockifier::transaction::objects::TransactionExecutionInfo; +use katana_primitives::block::{ExecutableBlock, GasPrices, PartialHeader}; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxWithHash}; +use katana_primitives::FieldElement; +use katana_provider::traits::state::StateProvider; +use starknet_api::block::{BlockNumber, BlockTimestamp}; +use tracing::info; + +use self::output::receipt_from_exec_info; +use self::state::CachedState; +use crate::{ + BlockExecutor, EntryPointCall, ExecutionError, ExecutionOutput, ExecutionResult, ExecutorExt, + ExecutorFactory, ExecutorResult, ResultAndStates, SimulationFlag, StateProviderDb, +}; + +#[derive(Debug)] +pub struct BlockifierFactory { + cfg: CfgEnv, + flags: SimulationFlag, +} + +impl BlockifierFactory { + /// Create a new factory with the given configuration and simulation flags. + pub fn new(cfg: CfgEnv, flags: SimulationFlag) -> Self { + Self { cfg, flags } + } +} + +impl ExecutorFactory for BlockifierFactory { + fn with_state<'a, P>(&self, state: P) -> Box + 'a> + where + P: StateProvider + 'a, + { + self.with_state_and_block_env(state, BlockEnv::default()) + } + + fn with_state_and_block_env<'a, P>( + &self, + state: P, + block_env: BlockEnv, + ) -> Box + 'a> + where + P: StateProvider + 'a, + { + let cfg_env = self.cfg.clone(); + let flags = self.flags.clone(); + Box::new(StarknetVMProcessor::new(Box::new(state), block_env, cfg_env, flags)) + } + + fn cfg(&self) -> &CfgEnv { + &self.cfg + } +} + +pub struct StarknetVMProcessor<'a> { + block_context: BlockContext, + state: CachedState>, + transactions: Vec<(TxWithHash, ExecutionResult)>, + simulation_flags: SimulationFlag, +} + +impl<'a> StarknetVMProcessor<'a> { + pub fn new( + state: Box, + block_env: BlockEnv, + cfg_env: CfgEnv, + simulation_flags: SimulationFlag, + ) -> Self { + let transactions = Vec::new(); + let block_context = utils::block_context_from_envs(&block_env, &cfg_env); + let state = state::CachedState::new(StateProviderDb(state)); + Self { block_context, state, transactions, simulation_flags } + } + + fn fill_block_env_from_header(&mut self, header: &PartialHeader) { + let number = BlockNumber(header.number); + let timestamp = BlockTimestamp(header.timestamp); + let eth_l1_gas_price = header.gas_prices.eth; + let strk_l1_gas_price = header.gas_prices.strk; + + self.block_context.block_info.block_number = number; + self.block_context.block_info.block_timestamp = timestamp; + self.block_context.block_info.gas_prices.eth_l1_gas_price = eth_l1_gas_price; + self.block_context.block_info.gas_prices.strk_l1_gas_price = strk_l1_gas_price; + self.block_context.block_info.sequencer_address = + utils::to_blk_address(header.sequencer_address); + } + + fn simulate_with( + &self, + transactions: Vec, + flags: &SimulationFlag, + mut op: F, + ) -> Vec + where + F: FnMut( + &mut dyn StateReader, + (TxWithHash, Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError>), + ) -> T, + { + let block_context = &self.block_context; + let state = &mut self.state.0.write().inner; + let mut state = cached_state::CachedState::new(MutRefState::new(state), Default::default()); + + let mut results = Vec::with_capacity(transactions.len()); + for exec_tx in transactions { + let tx = TxWithHash::from(&exec_tx); + let res = utils::transact(exec_tx, &mut state, block_context, flags); + results.push(op(&mut state, (tx, res))); + } + + results + } +} + +impl<'a> BlockExecutor<'a> for StarknetVMProcessor<'a> { + fn execute_block(&mut self, block: ExecutableBlock) -> ExecutorResult<()> { + self.fill_block_env_from_header(&block.header); + self.execute_transactions(block.body)?; + Ok(()) + } + + fn execute_transactions( + &mut self, + transactions: Vec, + ) -> ExecutorResult<()> { + let block_context = &self.block_context; + let flags = &self.simulation_flags; + let mut state = self.state.write(); + + for exec_tx in transactions { + // Collect class artifacts if its a declare tx + let class_decl_artifacts = if let ExecutableTx::Declare(tx) = exec_tx.as_ref() { + let class_hash = tx.class_hash(); + Some((class_hash, tx.compiled_class.clone(), tx.sierra_class.clone())) + } else { + None + }; + + let tx = TxWithHash::from(&exec_tx); + let res = match utils::transact(exec_tx, &mut state.inner, block_context, flags) { + Ok((info, fee)) => { + // get the trace and receipt from the execution info + let trace = utils::to_exec_info(info); + let receipt = receipt_from_exec_info(&tx, &trace); + + crate::utils::log_resources(&trace.actual_resources); + crate::utils::log_events(receipt.events()); + + if let Some(reason) = receipt.revert_reason() { + info!(target: "executor", "transaction reverted: {reason}"); + } + + ExecutionResult::new_success(receipt, trace, fee) + } + Err(e) => { + info!(target: "executor", "transaction execution failed: {e}"); + ExecutionResult::new_failed(e) + } + }; + + // if the tx succeed, inserts the class artifacts into the contract class cache + if res.is_success() { + if let Some((class_hash, compiled, sierra)) = class_decl_artifacts { + state.declared_classes.insert(class_hash, (compiled, sierra)); + } + } + + self.transactions.push((tx, res)); + } + + Ok(()) + } + + fn take_execution_output(&mut self) -> ExecutorResult { + let states = utils::state_update_from_cached_state(&self.state); + let transactions = std::mem::take(&mut self.transactions); + Ok(ExecutionOutput { states, transactions }) + } + + fn state(&self) -> Box { + Box::new(self.state.clone()) + } + + fn transactions(&self) -> &[(TxWithHash, ExecutionResult)] { + &self.transactions + } + + fn block_env(&self) -> BlockEnv { + BlockEnv { + number: self.block_context.block_info.block_number.0, + timestamp: self.block_context.block_info.block_timestamp.0, + sequencer_address: utils::to_address(self.block_context.block_info.sequencer_address), + l1_gas_prices: GasPrices { + eth: self.block_context.block_info.gas_prices.eth_l1_gas_price, + strk: self.block_context.block_info.gas_prices.strk_l1_gas_price, + }, + } + } +} + +impl ExecutorExt for StarknetVMProcessor<'_> { + fn simulate( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec { + self.simulate_with(transactions, &flags, |_, (tx, res)| { + let result = match res { + Ok((info, fee)) => { + let trace = utils::to_exec_info(info); + let receipt = receipt_from_exec_info(&tx, &trace); + ExecutionResult::new_success(receipt, trace, fee) + } + Err(e) => ExecutionResult::new_failed(e), + }; + + ResultAndStates { result, states: Default::default() } + }) + } + + fn estimate_fee( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec> { + self.simulate_with(transactions, &flags, |_, (_, res)| match res { + Ok((info, fee)) => { + // if the transaction was reverted, return as error + if let Some(reason) = info.revert_error { + info!(target: "executor", "fee estimation failed: {reason}"); + Err(ExecutionError::TransactionReverted { revert_error: reason }) + } else { + Ok(fee) + } + } + Err(e) => { + info!(target: "executor", "fee estimation failed: {e}"); + Err(e) + } + }) + } + + fn call(&self, call: EntryPointCall) -> Result, ExecutionError> { + let block_context = &self.block_context; + let mut state = self.state.0.write(); + let state = MutRefState::new(&mut state.inner); + let retdata = utils::call(call, state, block_context, 100_000_000)?; + Ok(retdata) + } +} diff --git a/crates/katana/executor/src/implementation/blockifier/output.rs b/crates/katana/executor/src/implementation/blockifier/output.rs new file mode 100644 index 0000000000..0de6d6055e --- /dev/null +++ b/crates/katana/executor/src/implementation/blockifier/output.rs @@ -0,0 +1,153 @@ +use std::collections::HashMap; + +use katana_primitives::receipt::{ + DeclareTxReceipt, DeployAccountTxReceipt, Event, InvokeTxReceipt, L1HandlerTxReceipt, + MessageToL1, Receipt, TxExecutionResources, +}; +use katana_primitives::trace::{CallInfo, TxExecInfo}; +use katana_primitives::transaction::Tx; + +pub(super) fn receipt_from_exec_info(tx: &Tx, info: &TxExecInfo) -> Receipt { + let actual_fee = info.actual_fee; + let events = events_from_exec_info(info); + let revert_error = info.revert_error.clone(); + let messages_sent = l2_to_l1_messages_from_exec_info(info); + let actual_resources = parse_actual_resources(&info.actual_resources); + + match tx { + Tx::Invoke(_) => Receipt::Invoke(InvokeTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + }), + + Tx::Declare(_) => Receipt::Declare(DeclareTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + }), + + Tx::L1Handler(tx) => Receipt::L1Handler(L1HandlerTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + message_hash: tx.message_hash, + execution_resources: actual_resources, + }), + + Tx::DeployAccount(tx) => Receipt::DeployAccount(DeployAccountTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + contract_address: tx.contract_address(), + }), + } +} + +fn events_from_exec_info(info: &TxExecInfo) -> Vec { + let mut events: Vec = vec![]; + + fn get_events_recursively(call_info: &CallInfo) -> Vec { + let mut events: Vec = vec![]; + + // By default, `from_address` must correspond to the contract address that + // is sending the message. In the case of library calls, `code_address` is `None`, + // we then use the `caller_address` instead (which can also be an account). + let from_address = if let Some(code_address) = call_info.code_address { + code_address + } else { + call_info.caller_address + }; + + events.extend(call_info.events.iter().map(|e| Event { + from_address, + data: e.data.clone(), + keys: e.keys.clone(), + })); + + call_info.inner_calls.iter().for_each(|call| { + events.extend(get_events_recursively(call)); + }); + + events + } + + if let Some(ref call) = info.validate_call_info { + events.extend(get_events_recursively(call)); + } + + if let Some(ref call) = info.execute_call_info { + events.extend(get_events_recursively(call)); + } + + if let Some(ref call) = info.fee_transfer_call_info { + events.extend(get_events_recursively(call)); + } + + events +} + +fn l2_to_l1_messages_from_exec_info(info: &TxExecInfo) -> Vec { + let mut messages = vec![]; + + fn get_messages_recursively(info: &CallInfo) -> Vec { + let mut messages = vec![]; + + // By default, `from_address` must correspond to the contract address that + // is sending the message. In the case of library calls, `code_address` is `None`, + // we then use the `caller_address` instead (which can also be an account). + let from_address = if let Some(code_address) = info.code_address { + code_address + } else { + info.caller_address + }; + + messages.extend(info.l2_to_l1_messages.iter().map(|m| MessageToL1 { + from_address, + payload: m.payload.clone(), + to_address: m.to_address, + })); + + info.inner_calls.iter().for_each(|call| { + messages.extend(get_messages_recursively(call)); + }); + + messages + } + + if let Some(ref info) = info.validate_call_info { + messages.extend(get_messages_recursively(info)); + } + + if let Some(ref info) = info.execute_call_info { + messages.extend(get_messages_recursively(info)); + } + + if let Some(ref info) = info.fee_transfer_call_info { + messages.extend(get_messages_recursively(info)); + } + + messages +} + +fn parse_actual_resources(resources: &HashMap) -> TxExecutionResources { + TxExecutionResources { + steps: resources.get("n_steps").copied().unwrap_or_default(), + memory_holes: resources.get("memory_holes").copied(), + ec_op_builtin: resources.get("ec_op_builtin").copied(), + ecdsa_builtin: resources.get("ecdsa_builtin").copied(), + keccak_builtin: resources.get("keccak_builtin").copied(), + bitwise_builtin: resources.get("bitwise_builtin").copied(), + pedersen_builtin: resources.get("pedersen_builtin").copied(), + poseidon_builtin: resources.get("poseidon_builtin").copied(), + range_check_builtin: resources.get("range_check_builtin").copied(), + segment_arena_builtin: resources.get("segment_arena_builtin").copied(), + } +} diff --git a/crates/katana/executor/src/implementation/blockifier/state.rs b/crates/katana/executor/src/implementation/blockifier/state.rs new file mode 100644 index 0000000000..074e52dad2 --- /dev/null +++ b/crates/katana/executor/src/implementation/blockifier/state.rs @@ -0,0 +1,548 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use blockifier::state::cached_state::{self, GlobalContractCache}; +use blockifier::state::errors::StateError; +use blockifier::state::state_api::{StateReader, StateResult}; +use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; +use katana_primitives::FieldElement; +use katana_provider::error::ProviderError; +use katana_provider::traits::contract::ContractClassProvider; +use katana_provider::traits::state::StateProvider; +use katana_provider::ProviderResult; +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +use starknet_api::core::{ClassHash, CompiledClassHash, Nonce, PatriciaKey}; +use starknet_api::hash::StarkHash; +use starknet_api::patricia_key; +use starknet_api::state::StorageKey; + +use super::utils::{self}; +use crate::StateProviderDb; + +/// A helper trait to enforce that a type must implement both [StateProvider] and [StateReader]. +pub(super) trait StateDb: StateProvider + StateReader {} + +impl StateDb for T where T: StateProvider + StateReader {} + +impl<'a> StateReader for StateProviderDb<'a> { + fn get_class_hash_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + ) -> StateResult { + self.0 + .class_hash_of_contract(utils::to_address(contract_address)) + .map(|v| ClassHash(v.unwrap_or_default().into())) + .map_err(|e| StateError::StateReadError(e.to_string())) + } + + fn get_compiled_class_hash( + &mut self, + class_hash: starknet_api::core::ClassHash, + ) -> StateResult { + if let Some(hash) = self + .0 + .compiled_class_hash_of_class_hash(class_hash.0.into()) + .map_err(|e| StateError::StateReadError(e.to_string()))? + { + Ok(CompiledClassHash(hash.into())) + } else { + Err(StateError::UndeclaredClassHash(class_hash)) + } + } + + fn get_compiled_contract_class( + &mut self, + class_hash: ClassHash, + ) -> StateResult { + if let Some(class) = self + .0 + .class(class_hash.0.into()) + .map_err(|e| StateError::StateReadError(e.to_string()))? + { + let class = + utils::to_class(class).map_err(|e| StateError::StateReadError(e.to_string()))?; + + Ok(class) + } else { + Err(StateError::UndeclaredClassHash(class_hash)) + } + } + + fn get_nonce_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + ) -> StateResult { + self.0 + .nonce(utils::to_address(contract_address)) + .map(|n| Nonce(n.unwrap_or_default().into())) + .map_err(|e| StateError::StateReadError(e.to_string())) + } + + fn get_storage_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + key: starknet_api::state::StorageKey, + ) -> StateResult { + self.0 + .storage(utils::to_address(contract_address), (*key.0.key()).into()) + .map(|v| v.unwrap_or_default().into()) + .map_err(|e| StateError::StateReadError(e.to_string())) + } +} + +pub(super) struct CachedState(pub(super) Arc>>); + +impl Clone for CachedState { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } +} + +type DeclaredClass = (CompiledClass, Option); + +#[derive(Debug)] +pub(super) struct CachedStateInner { + pub(super) inner: cached_state::CachedState, + pub(super) declared_classes: HashMap, +} + +impl CachedState { + pub(super) fn new(state: S) -> Self { + let declared_classes = HashMap::new(); + let cached_state = cached_state::CachedState::new(state, GlobalContractCache::default()); + let inner = CachedStateInner { inner: cached_state, declared_classes }; + Self(Arc::new(RwLock::new(inner))) + } + + pub(super) fn read(&self) -> RwLockReadGuard<'_, CachedStateInner> { + self.0.read() + } + + pub(super) fn write(&self) -> RwLockWriteGuard<'_, CachedStateInner> { + self.0.write() + } +} + +impl ContractClassProvider for CachedState { + fn class( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let state = self.read(); + if let Some((class, _)) = state.declared_classes.get(&hash) { + Ok(Some(class.clone())) + } else { + state.inner.state.class(hash) + } + } + + fn compiled_class_hash_of_class_hash( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let Ok(hash) = self.write().inner.get_compiled_class_hash(ClassHash(hash.into())) else { + return Ok(None); + }; + Ok(Some(hash.0.into())) + } + + fn sierra_class( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let state = self.read(); + if let Some((_, sierra)) = state.declared_classes.get(&hash) { + Ok(sierra.clone()) + } else { + state.inner.state.sierra_class(hash) + } + } +} + +impl StateProvider for CachedState { + fn class_hash_of_contract( + &self, + address: katana_primitives::contract::ContractAddress, + ) -> ProviderResult> { + let Ok(hash) = self.write().inner.get_class_hash_at(utils::to_blk_address(address)) else { + return Ok(None); + }; + + let hash = hash.0.into(); + if hash == FieldElement::ZERO { Ok(None) } else { Ok(Some(hash)) } + } + + fn nonce( + &self, + address: katana_primitives::contract::ContractAddress, + ) -> ProviderResult> { + // check if the contract is deployed + if self.class_hash_of_contract(address)?.is_none() { + return Ok(None); + } + + match self.0.write().inner.get_nonce_at(utils::to_blk_address(address)) { + Ok(nonce) => Ok(Some(nonce.0.into())), + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } + + fn storage( + &self, + address: katana_primitives::contract::ContractAddress, + storage_key: katana_primitives::contract::StorageKey, + ) -> ProviderResult> { + // check if the contract is deployed + if self.class_hash_of_contract(address)?.is_none() { + return Ok(None); + } + + let address = utils::to_blk_address(address); + let key = StorageKey(patricia_key!(storage_key)); + + match self.write().inner.get_storage_at(address, key) { + Ok(value) => Ok(Some(value.into())), + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } +} + +impl StateReader for CachedState { + fn get_class_hash_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + ) -> StateResult { + self.write().inner.get_class_hash_at(contract_address) + } + + fn get_compiled_class_hash(&mut self, class_hash: ClassHash) -> StateResult { + self.write().inner.get_compiled_class_hash(class_hash) + } + + fn get_compiled_contract_class( + &mut self, + class_hash: ClassHash, + ) -> StateResult { + self.write().inner.get_compiled_contract_class(class_hash) + } + + fn get_nonce_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + ) -> StateResult { + self.write().inner.get_nonce_at(contract_address) + } + + fn get_storage_at( + &mut self, + contract_address: starknet_api::core::ContractAddress, + key: StorageKey, + ) -> StateResult { + self.write().inner.get_storage_at(contract_address, key) + } +} + +#[cfg(test)] +mod tests { + + use blockifier::state::state_api::{State, StateReader}; + use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; + use katana_primitives::contract::ContractAddress; + use katana_primitives::genesis::constant::{ + DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, DEFAULT_OZ_ACCOUNT_CONTRACT, + DEFAULT_OZ_ACCOUNT_CONTRACT_CASM, + }; + use katana_primitives::utils::class::{parse_compiled_class, parse_sierra_class}; + use katana_primitives::FieldElement; + use katana_provider::providers::in_memory::InMemoryProvider; + use katana_provider::traits::contract::ContractClassWriter; + use katana_provider::traits::state::{StateFactoryProvider, StateProvider, StateWriter}; + use starknet::macros::felt; + + use super::{CachedState, *}; + use crate::StateProviderDb; + + fn new_sierra_class() -> (FlattenedSierraClass, CompiledClass) { + let json = include_str!("../../../../primitives/contracts/compiled/cairo1_contract.json"); + let artifact = serde_json::from_str(json).unwrap(); + let compiled_class = parse_compiled_class(artifact).unwrap(); + let sierra_class = parse_sierra_class(json).unwrap().flatten().unwrap(); + (sierra_class, compiled_class) + } + + fn state_provider() -> Box { + let address = ContractAddress::from(felt!("0x67")); + let nonce = felt!("0x7"); + let storage_key = felt!("0x1"); + let storage_value = felt!("0x2"); + let class_hash = felt!("0x123"); + let compiled_hash = felt!("0x456"); + let sierra_class = DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(); + let class = DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone(); + let legacy_class_hash = felt!("0x111"); + let legacy_class = DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone(); + + let provider = InMemoryProvider::new(); + provider.set_nonce(address, nonce).unwrap(); + provider.set_class_hash_of_contract(address, class_hash).unwrap(); + provider.set_storage(address, storage_key, storage_value).unwrap(); + provider.set_compiled_class_hash_of_class_hash(class_hash, compiled_hash).unwrap(); + provider.set_class(class_hash, class).unwrap(); + provider.set_sierra_class(class_hash, sierra_class).unwrap(); + provider.set_class(legacy_class_hash, legacy_class).unwrap(); + + provider.latest().unwrap() + } + + #[test] + fn can_fetch_from_inner_state_provider() -> anyhow::Result<()> { + let state = state_provider(); + let mut cached_state = CachedState::new(StateProviderDb(state)); + + let address = ContractAddress::from(felt!("0x67")); + let legacy_class_hash = felt!("0x111"); + let storage_key = felt!("0x1"); + + let api_address = utils::to_blk_address(address); + let actual_class_hash = cached_state.get_class_hash_at(api_address)?; + let actual_nonce = cached_state.get_nonce_at(api_address)?; + let actual_storage_value = + cached_state.get_storage_at(api_address, StorageKey(patricia_key!(storage_key)))?; + let actual_compiled_hash = cached_state.get_compiled_class_hash(actual_class_hash)?; + let actual_class = cached_state.get_compiled_contract_class(actual_class_hash)?; + let actual_legacy_class = + cached_state.get_compiled_contract_class(ClassHash(legacy_class_hash.into()))?; + + assert_eq!(actual_nonce.0, felt!("0x7").into()); + assert_eq!(actual_storage_value, felt!("0x2").into()); + assert_eq!(actual_class_hash.0, felt!("0x123").into()); + assert_eq!(actual_compiled_hash.0, felt!("0x456").into()); + assert_eq!( + actual_class, + utils::to_class(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone()).unwrap() + ); + assert_eq!( + actual_legacy_class, + utils::to_class(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone()).unwrap() + ); + + Ok(()) + } + + #[test] + fn can_fetch_as_state_provider() -> anyhow::Result<()> { + let sp = state_provider(); + + // cache_state native data + let new_address = ContractAddress::from(felt!("0xdead")); + let new_storage_key = felt!("0xf00"); + let new_storage_value = felt!("0xba"); + let new_legacy_class_hash = felt!("0x1234"); + let new_legacy_class = DEFAULT_LEGACY_UDC_CASM.clone(); + let new_legacy_compiled_hash = felt!("0x5678"); + let new_class_hash = felt!("0x777"); + let (new_sierra_class, new_compiled_sierra_class) = new_sierra_class(); + let new_compiled_hash = felt!("0xdead"); + + // we're asserting that the underlying state provider doesnt have cache state native data + + let actual_new_nonce = sp.nonce(new_address)?; + let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; + let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; + let actual_new_legacy_class = sp.class(new_legacy_class_hash)?; + let actual_new_legacy_sierra_class = sp.class(new_legacy_class_hash)?; + let actual_new_sierra_class = sp.sierra_class(new_class_hash)?; + let actual_new_class = sp.class(new_class_hash)?; + let actual_new_compiled_class_hash = + sp.compiled_class_hash_of_class_hash(new_class_hash)?; + let actual_new_legacy_compiled_hash = + sp.compiled_class_hash_of_class_hash(new_legacy_class_hash)?; + + assert_eq!(actual_new_nonce, None, "data shouldn't exist"); + assert_eq!(actual_new_class_hash, None, "data shouldn't exist"); + assert_eq!(actual_new_storage_value, None, "data shouldn't exist"); + assert_eq!(actual_new_legacy_class, None, "data should'nt exist"); + assert_eq!(actual_new_legacy_sierra_class, None, "data shouldn't exist"); + assert_eq!(actual_new_sierra_class, None, "data shouldn't exist"); + assert_eq!(actual_new_class, None, "data shouldn't exist"); + assert_eq!(actual_new_compiled_class_hash, None, "data shouldn't exist"); + assert_eq!(actual_new_legacy_compiled_hash, None, "data shouldn't exist"); + + let cached_state = CachedState::new(StateProviderDb(sp)); + + // insert some data to the cached state + { + let lock = &mut cached_state.0.write(); + let blk_state = &mut lock.inner; + + let address = utils::to_blk_address(new_address); + let storage_key = StorageKey(patricia_key!(new_storage_key)); + let storage_value = new_storage_value.into(); + let class_hash = ClassHash(new_class_hash.into()); + let class = utils::to_class(new_compiled_sierra_class.clone()).unwrap(); + let compiled_hash = CompiledClassHash(new_compiled_hash.into()); + let legacy_class_hash = ClassHash(new_legacy_class_hash.into()); + let legacy_class = utils::to_class(DEFAULT_LEGACY_UDC_CASM.clone()).unwrap(); + let legacy_compiled_hash = CompiledClassHash(new_legacy_compiled_hash.into()); + + blk_state.increment_nonce(address)?; + blk_state.set_class_hash_at(address, legacy_class_hash)?; + blk_state.set_storage_at(address, storage_key, storage_value)?; + blk_state.set_contract_class(class_hash, class)?; + blk_state.set_compiled_class_hash(class_hash, compiled_hash)?; + blk_state.set_contract_class(legacy_class_hash, legacy_class)?; + blk_state.set_compiled_class_hash(legacy_class_hash, legacy_compiled_hash)?; + + let declared_classes = &mut lock.declared_classes; + declared_classes.insert(new_legacy_class_hash, (new_legacy_class.clone(), None)); + declared_classes.insert( + new_class_hash, + (new_compiled_sierra_class.clone(), Some(new_sierra_class.clone())), + ); + } + + // assert that can fetch data from the underlyign state provider + let sp: Box = Box::new(cached_state); + + let address = ContractAddress::from(felt!("0x67")); + let class_hash = felt!("0x123"); + let legacy_class_hash = felt!("0x111"); + + let actual_class_hash = sp.class_hash_of_contract(address)?; + let actual_nonce = sp.nonce(address)?; + let actual_storage_value = sp.storage(address, felt!("0x1"))?; + let actual_class = sp.class(class_hash)?; + let actual_sierra_class = sp.sierra_class(class_hash)?; + let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; + let actual_legacy_class = sp.class(legacy_class_hash)?; + + assert_eq!(actual_nonce, Some(felt!("0x7"))); + assert_eq!(actual_class_hash, Some(class_hash)); + assert_eq!(actual_storage_value, Some(felt!("0x2"))); + assert_eq!(actual_compiled_hash, Some(felt!("0x456"))); + assert_eq!(actual_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone())); + assert_eq!(actual_sierra_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten()?)); + assert_eq!(actual_legacy_class, Some(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone())); + + // assert that can fetch data native to the cached state from the state provider + + let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; + let actual_new_nonce = sp.nonce(new_address)?; + let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; + let actual_new_class = sp.class(new_class_hash)?; + let actual_new_sierra = sp.sierra_class(new_class_hash)?; + let actual_new_compiled_hash = sp.compiled_class_hash_of_class_hash(new_class_hash)?; + let actual_legacy_class = sp.class(new_legacy_class_hash)?; + let actual_legacy_sierra = sp.sierra_class(new_legacy_class_hash)?; + let actual_new_legacy_compiled_hash = + sp.compiled_class_hash_of_class_hash(new_legacy_class_hash)?; + + assert_eq!(actual_new_nonce, Some(felt!("0x1")), "data should be in cached state"); + assert_eq!( + actual_new_class_hash, + Some(new_legacy_class_hash), + "data should be in cached state" + ); + assert_eq!( + actual_new_storage_value, + Some(new_storage_value), + "data should be in cached state" + ); + assert_eq!(actual_new_class, Some(new_compiled_sierra_class)); + assert_eq!(actual_new_sierra, Some(new_sierra_class)); + assert_eq!(actual_new_compiled_hash, Some(new_compiled_hash)); + assert_eq!(actual_legacy_class, Some(new_legacy_class)); + assert_eq!(actual_legacy_sierra, None, "legacy class should not have sierra class"); + assert_eq!( + actual_new_legacy_compiled_hash, + Some(new_legacy_compiled_hash), + "data should + be in cached state" + ); + + Ok(()) + } + + #[test] + fn fetch_non_existant_data() -> anyhow::Result<()> { + let db = InMemoryProvider::new(); + + let address = ContractAddress::from(felt!("0x1")); + let class_hash = felt!("0x123"); + let storage_key = felt!("0x1"); + + // edge case: the StateProvider::storage impl of CachedState will return + // default value for non-existant storage key of an existant contract. It will + // only return None if the contract does not exist. The intended behaviour for + // StateProvider::storage is to return None if the storage key or contract address + // does not exist. + let edge_address = ContractAddress::from(felt!("0x2")); + db.set_class_hash_of_contract(edge_address, class_hash)?; + + let sp = db.latest()?; + + let mut cached_state = CachedState::new(StateProviderDb(sp)); + + let api_address = utils::to_blk_address(address); + let api_storage_key = StorageKey(patricia_key!(storage_key)); + let api_class_hash = ClassHash(class_hash.into()); + + let actual_nonce = + cached_state.get_nonce_at(api_address).expect("should return default value"); + let actual_storage_value = cached_state + .get_storage_at(api_address, api_storage_key) + .expect("should return default value"); + let actual_class_hash = + cached_state.get_class_hash_at(api_address).expect("should return default value"); + let actual_compiled_hash = cached_state.get_compiled_class_hash(api_class_hash); + let actual_compiled_class = cached_state.get_compiled_contract_class(api_class_hash); + let actual_edge_storage_value = cached_state + .get_storage_at(utils::to_blk_address(edge_address), api_storage_key) + .expect("should return default value"); + + assert_eq!( + actual_nonce, + Default::default(), + "nonce of nonexistant contract should default to zero" + ); + assert_eq!( + actual_storage_value, + Default::default(), + "value of nonexistant contract and storage key should default to zero" + ); + assert_eq!( + actual_edge_storage_value, + Default::default(), + "value of nonexistant storage key but existant contract should default to zero" + ); + assert_eq!( + actual_class_hash, + ClassHash::default(), + "class hash of nonexistant contract should default to zero" + ); + assert!(actual_compiled_hash.unwrap_err().to_string().contains("is not declared")); + assert!(actual_compiled_class.unwrap_err().to_string().contains("is not declared")); + + let sp: Box = Box::new(cached_state); + + let actual_nonce = sp.nonce(address)?; + let actual_storage_value = sp.storage(address, storage_key)?; + let actual_edge_storage_value = sp.storage(edge_address, storage_key)?; + let actual_class_hash = sp.class_hash_of_contract(address)?; + let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; + let actual_class = sp.class(class_hash)?; + + assert_eq!(actual_nonce, None, "nonce of nonexistant contract should be None"); + assert_eq!(actual_class_hash, None, "class hash of nonexistant contract should be None"); + assert_eq!(actual_storage_value, None, "value of nonexistant contract should be None"); + assert_eq!( + actual_edge_storage_value, + Some(FieldElement::ZERO), + "edge case: value of nonexistant storage key but existant contract should return zero" + ); + assert_eq!(actual_compiled_hash, None); + assert_eq!(actual_class, None); + + Ok(()) + } +} diff --git a/crates/katana/executor/src/implementation/blockifier/utils.rs b/crates/katana/executor/src/implementation/blockifier/utils.rs new file mode 100644 index 0000000000..7016583079 --- /dev/null +++ b/crates/katana/executor/src/implementation/blockifier/utils.rs @@ -0,0 +1,615 @@ +use std::collections::{BTreeMap, HashMap}; +use std::sync::Arc; + +use blockifier::block_context::{BlockContext, BlockInfo, ChainInfo, FeeTokenAddresses, GasPrices}; +use blockifier::execution::call_info::CallInfo; +use blockifier::execution::common_hints::ExecutionMode; +use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV1}; +use blockifier::execution::entry_point::{ + CallEntryPoint, CallType, EntryPointExecutionContext, ExecutionResources, +}; +use blockifier::fee::fee_utils::{calculate_tx_fee, calculate_tx_l1_gas_usages}; +use blockifier::state::cached_state::{self}; +use blockifier::state::state_api::{State, StateReader}; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::objects::{ + AccountTransactionContext, DeprecatedAccountTransactionContext, FeeType, HasRelatedFeeType, + TransactionExecutionInfo, +}; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::{ + DeclareTransaction, DeployAccountTransaction, ExecutableTransaction, InvokeTransaction, + L1HandlerTransaction, +}; +use cairo_vm::types::errors::program_errors::ProgramError; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; +use katana_primitives::transaction::{ + DeclareTx, DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, +}; +use katana_primitives::FieldElement; +use katana_provider::traits::contract::ContractClassProvider; +use starknet::core::types::PriceUnit; +use starknet::core::utils::parse_cairo_short_string; +use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ + self, ChainId, ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey, +}; +use starknet_api::data_availability::DataAvailabilityMode; +use starknet_api::deprecated_contract_class::EntryPointType; +use starknet_api::hash::StarkHash; +use starknet_api::patricia_key; +use starknet_api::transaction::{ + AccountDeploymentData, Calldata, ContractAddressSalt, + DeclareTransaction as ApiDeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, + DeclareTransactionV3, DeployAccountTransaction as ApiDeployAccountTransaction, + DeployAccountTransactionV1, DeployAccountTransactionV3, Fee, + InvokeTransaction as ApiInvokeTransaction, PaymasterData, Resource, ResourceBounds, + ResourceBoundsMapping, Tip, TransactionHash, TransactionSignature, TransactionVersion, +}; + +use super::state::{CachedState, StateDb}; +use crate::abstraction::{EntryPointCall, SimulationFlag}; +use crate::ExecutionError; + +pub(super) fn transact( + tx: ExecutableTxWithHash, + state: &mut cached_state::CachedState, + block_context: &BlockContext, + simulation_flags: &SimulationFlag, +) -> Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError> { + let validate = !simulation_flags.skip_validate; + let charge_fee = !simulation_flags.skip_fee_transfer; + + let transaction = to_executor_tx(tx); + let fee_type = get_fee_type_from_tx(&transaction); + + let info = match transaction { + Transaction::AccountTransaction(tx) => { + tx.execute(state, block_context, charge_fee, validate) + } + Transaction::L1HandlerTransaction(tx) => { + tx.execute(state, block_context, charge_fee, validate) + } + }?; + + // There are a few case where the `actual_fee` field of the transaction info is not set where + // the fee is skipped and thus not charged for the transaction (e.g. when the + // `skip_fee_transfer` is explicitly set, or when the transaction `max_fee` is set to 0). In + // these cases, we still want to calculate the fee. + let overall_fee = if info.actual_fee == Fee(0) { + calculate_tx_fee(&info.actual_resources, block_context, &fee_type)?.0 + } else { + info.actual_fee.0 + }; + + let gas_consumed = calculate_tx_l1_gas_usages(&info.actual_resources, block_context)?.gas_usage; + + let (unit, gas_price) = match fee_type { + FeeType::Eth => (PriceUnit::Wei, block_context.block_info.gas_prices.eth_l1_gas_price), + FeeType::Strk => (PriceUnit::Fri, block_context.block_info.gas_prices.strk_l1_gas_price), + }; + + let fee = TxFeeInfo { gas_consumed, gas_price, unit, overall_fee }; + Ok((info, fee)) +} + +/// Perform a function call on a contract and retrieve the return values. +pub fn call( + request: EntryPointCall, + state: S, + block_context: &BlockContext, + initial_gas: u128, +) -> Result, ExecutionError> { + let mut state = cached_state::CachedState::new(state, Default::default()); + + let call = CallEntryPoint { + initial_gas: initial_gas as u64, + storage_address: to_blk_address(request.contract_address), + entry_point_selector: core::EntryPointSelector(request.entry_point_selector.into()), + calldata: Calldata(Arc::new(request.calldata.into_iter().map(|f| f.into()).collect())), + ..Default::default() + }; + + // TODO: this must be false if fees are disabled I assume. + let limit_steps_by_resources = true; + + // Now, the max step is not given directly to this function. + // It's computed by a new function max_steps, and it tooks the values + // from teh block context itself instead of the input give. + // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/execution/entry_point.rs#L165 + // The blockifier patch must be adjusted to modify this function to return + // the limit we have into the block context without min applied: + // https://github.com/starkware-libs/blockifier/blob/51b343fe38139a309a69b2482f4b484e8caa5edf/crates/blockifier/src/execution/entry_point.rs#L215 + let res = call.execute( + &mut state, + &mut ExecutionResources::default(), + &mut EntryPointExecutionContext::new( + block_context, + &AccountTransactionContext::Deprecated(DeprecatedAccountTransactionContext::default()), + ExecutionMode::Execute, + limit_steps_by_resources, + ) + .expect("shouldn't fail"), + )?; + + let retdata = res.execution.retdata.0; + let retdata = retdata.into_iter().map(|f| f.into()).collect::>(); + Ok(retdata) +} + +fn to_executor_tx(tx: ExecutableTxWithHash) -> Transaction { + let hash = tx.hash; + + match tx.transaction { + ExecutableTx::Invoke(tx) => match tx { + InvokeTx::V1(tx) => { + let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + + Transaction::AccountTransaction(AccountTransaction::Invoke(InvokeTransaction { + tx: ApiInvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: Fee(tx.max_fee), + nonce: Nonce(tx.nonce.into()), + sender_address: to_blk_address(tx.sender_address), + signature: TransactionSignature(signature), + calldata: Calldata(Arc::new(calldata)), + }), + tx_hash: TransactionHash(hash.into()), + only_query: false, + })) + } + + InvokeTx::V3(tx) => { + let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + + let paymaster_data = tx.paymaster_data.into_iter().map(|f| f.into()).collect(); + let account_deploy_data = + tx.account_deployment_data.into_iter().map(|f| f.into()).collect(); + let fee_data_availability_mode = to_api_da_mode(tx.fee_data_availability_mode); + let nonce_data_availability_mode = to_api_da_mode(tx.nonce_data_availability_mode); + + Transaction::AccountTransaction(AccountTransaction::Invoke(InvokeTransaction { + tx: ApiInvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + tip: Tip(tx.tip), + nonce: Nonce(tx.nonce.into()), + sender_address: to_blk_address(tx.sender_address), + signature: TransactionSignature(signature), + calldata: Calldata(Arc::new(calldata)), + paymaster_data: PaymasterData(paymaster_data), + account_deployment_data: AccountDeploymentData(account_deploy_data), + fee_data_availability_mode, + nonce_data_availability_mode, + resource_bounds: to_api_resource_bounds(tx.resource_bounds), + }), + tx_hash: TransactionHash(hash.into()), + only_query: false, + })) + } + }, + + ExecutableTx::DeployAccount(tx) => match tx { + DeployAccountTx::V1(tx) => { + let calldata = tx.constructor_calldata.into_iter().map(|f| f.into()).collect(); + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + let salt = ContractAddressSalt(tx.contract_address_salt.into()); + + Transaction::AccountTransaction(AccountTransaction::DeployAccount( + DeployAccountTransaction { + contract_address: to_blk_address(tx.contract_address), + tx: ApiDeployAccountTransaction::V1(DeployAccountTransactionV1 { + max_fee: Fee(tx.max_fee), + nonce: Nonce(tx.nonce.into()), + signature: TransactionSignature(signature), + class_hash: ClassHash(tx.class_hash.into()), + constructor_calldata: Calldata(Arc::new(calldata)), + contract_address_salt: salt, + }), + tx_hash: TransactionHash(hash.into()), + only_query: false, + }, + )) + } + + DeployAccountTx::V3(tx) => { + let calldata = tx.constructor_calldata.into_iter().map(|f| f.into()).collect(); + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + let salt = ContractAddressSalt(tx.contract_address_salt.into()); + + let paymaster_data = tx.paymaster_data.into_iter().map(|f| f.into()).collect(); + let fee_data_availability_mode = to_api_da_mode(tx.fee_data_availability_mode); + let nonce_data_availability_mode = to_api_da_mode(tx.nonce_data_availability_mode); + + Transaction::AccountTransaction(AccountTransaction::DeployAccount( + DeployAccountTransaction { + contract_address: to_blk_address(tx.contract_address), + tx: ApiDeployAccountTransaction::V3(DeployAccountTransactionV3 { + tip: Tip(tx.tip), + nonce: Nonce(tx.nonce.into()), + signature: TransactionSignature(signature), + class_hash: ClassHash(tx.class_hash.into()), + constructor_calldata: Calldata(Arc::new(calldata)), + contract_address_salt: salt, + paymaster_data: PaymasterData(paymaster_data), + fee_data_availability_mode, + nonce_data_availability_mode, + resource_bounds: to_api_resource_bounds(tx.resource_bounds), + }), + tx_hash: TransactionHash(hash.into()), + only_query: false, + }, + )) + } + }, + + ExecutableTx::Declare(tx) => { + let contract_class = tx.compiled_class; + + let tx = match tx.transaction { + DeclareTx::V1(tx) => { + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + + ApiDeclareTransaction::V1(DeclareTransactionV0V1 { + max_fee: Fee(tx.max_fee), + nonce: Nonce(tx.nonce.into()), + sender_address: to_blk_address(tx.sender_address), + signature: TransactionSignature(signature), + class_hash: ClassHash(tx.class_hash.into()), + }) + } + + DeclareTx::V2(tx) => { + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + + ApiDeclareTransaction::V2(DeclareTransactionV2 { + max_fee: Fee(tx.max_fee), + nonce: Nonce(tx.nonce.into()), + sender_address: to_blk_address(tx.sender_address), + signature: TransactionSignature(signature), + class_hash: ClassHash(tx.class_hash.into()), + compiled_class_hash: CompiledClassHash(tx.compiled_class_hash.into()), + }) + } + + DeclareTx::V3(tx) => { + let signature = tx.signature.into_iter().map(|f| f.into()).collect(); + + let paymaster_data = tx.paymaster_data.into_iter().map(|f| f.into()).collect(); + let fee_data_availability_mode = to_api_da_mode(tx.fee_data_availability_mode); + let nonce_data_availability_mode = + to_api_da_mode(tx.nonce_data_availability_mode); + let account_deploy_data = + tx.account_deployment_data.into_iter().map(|f| f.into()).collect(); + + ApiDeclareTransaction::V3(DeclareTransactionV3 { + tip: Tip(tx.tip), + nonce: Nonce(tx.nonce.into()), + sender_address: to_blk_address(tx.sender_address), + signature: TransactionSignature(signature), + class_hash: ClassHash(tx.class_hash.into()), + account_deployment_data: AccountDeploymentData(account_deploy_data), + compiled_class_hash: CompiledClassHash(tx.compiled_class_hash.into()), + paymaster_data: PaymasterData(paymaster_data), + fee_data_availability_mode, + nonce_data_availability_mode, + resource_bounds: to_api_resource_bounds(tx.resource_bounds), + }) + } + }; + + let hash = TransactionHash(hash.into()); + let class = to_class(contract_class).unwrap(); + let tx = DeclareTransaction::new(tx, hash, class).expect("class mismatch"); + Transaction::AccountTransaction(AccountTransaction::Declare(tx)) + } + + ExecutableTx::L1Handler(tx) => { + let calldata = tx.calldata.into_iter().map(|f| f.into()).collect(); + Transaction::L1HandlerTransaction(L1HandlerTransaction { + paid_fee_on_l1: Fee(tx.paid_fee_on_l1), + tx: starknet_api::transaction::L1HandlerTransaction { + nonce: core::Nonce(tx.nonce.into()), + calldata: Calldata(Arc::new(calldata)), + version: TransactionVersion(1u128.into()), + contract_address: to_blk_address(tx.contract_address), + entry_point_selector: core::EntryPointSelector(tx.entry_point_selector.into()), + }, + tx_hash: TransactionHash(hash.into()), + }) + } + } +} + +/// Create a block context from the chain environment values. +pub(crate) fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { + let fee_token_addresses = FeeTokenAddresses { + eth_fee_token_address: to_blk_address(cfg_env.fee_token_addresses.eth), + strk_fee_token_address: to_blk_address(cfg_env.fee_token_addresses.strk), + }; + + let gas_prices = GasPrices { + eth_l1_gas_price: block_env.l1_gas_prices.eth, + strk_l1_gas_price: block_env.l1_gas_prices.strk, + eth_l1_data_gas_price: 0, + strk_l1_data_gas_price: 0, + }; + + BlockContext { + block_info: BlockInfo { + gas_prices, + use_kzg_da: false, + block_number: BlockNumber(block_env.number), + block_timestamp: BlockTimestamp(block_env.timestamp), + sequencer_address: to_blk_address(block_env.sequencer_address), + max_recursion_depth: cfg_env.max_recursion_depth, + validate_max_n_steps: cfg_env.validate_max_n_steps, + invoke_tx_max_n_steps: cfg_env.invoke_tx_max_n_steps, + vm_resource_fee_cost: cfg_env.vm_resource_fee_cost.clone().into(), + }, + chain_info: ChainInfo { fee_token_addresses, chain_id: to_blk_chain_id(cfg_env.chain_id) }, + } +} + +pub(super) fn state_update_from_cached_state( + state: &CachedState, +) -> StateUpdatesWithDeclaredClasses { + use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; + + let state_diff = state.0.write().inner.to_state_diff(); + + let mut declared_compiled_classes: HashMap = + HashMap::new(); + let mut declared_sierra_classes: HashMap< + katana_primitives::class::ClassHash, + FlattenedSierraClass, + > = HashMap::new(); + + for (class_hash, _) in &state_diff.class_hash_to_compiled_class_hash { + let hash = class_hash.0.into(); + let class = state.class(hash).unwrap().expect("must exist if declared"); + + if let CompiledClass::Class(_) = class { + let sierra = state.sierra_class(hash).unwrap().expect("must exist if declared"); + declared_sierra_classes.insert(hash, sierra); + } + + declared_compiled_classes.insert(hash, class); + } + + let nonce_updates = + state_diff + .address_to_nonce + .into_iter() + .map(|(key, value)| (to_address(key), value.0.into())) + .collect::>(); + + let storage_updates = state_diff + .storage_updates + .into_iter() + .map(|(addr, entries)| { + let entries = entries + .into_iter() + .map(|(k, v)| ((*k.0.key()).into(), v.into())) + .collect::>(); + + (to_address(addr), entries) + }) + .collect::>(); + + let contract_updates = + state_diff + .address_to_class_hash + .into_iter() + .map(|(key, value)| (to_address(key), value.0.into())) + .collect::>(); + + let declared_classes = + state_diff + .class_hash_to_compiled_class_hash + .into_iter() + .map(|(key, value)| (key.0.into(), value.0.into())) + .collect::>(); + + StateUpdatesWithDeclaredClasses { + declared_sierra_classes, + declared_compiled_classes, + state_updates: StateUpdates { + nonce_updates, + storage_updates, + contract_updates, + declared_classes, + }, + } +} + +fn to_api_da_mode(mode: starknet::core::types::DataAvailabilityMode) -> DataAvailabilityMode { + match mode { + starknet::core::types::DataAvailabilityMode::L1 => DataAvailabilityMode::L1, + starknet::core::types::DataAvailabilityMode::L2 => DataAvailabilityMode::L2, + } +} + +fn to_api_resource_bounds( + resource_bounds: starknet::core::types::ResourceBoundsMapping, +) -> ResourceBoundsMapping { + let l1_gas = ResourceBounds { + max_amount: resource_bounds.l1_gas.max_amount, + max_price_per_unit: resource_bounds.l1_gas.max_price_per_unit, + }; + + let l2_gas = ResourceBounds { + max_amount: resource_bounds.l2_gas.max_amount, + max_price_per_unit: resource_bounds.l2_gas.max_price_per_unit, + }; + + ResourceBoundsMapping(BTreeMap::from([(Resource::L1Gas, l1_gas), (Resource::L2Gas, l2_gas)])) +} + +/// Get the fee type of a transaction. The fee type determines the token used to pay for the +/// transaction. +fn get_fee_type_from_tx(transaction: &Transaction) -> FeeType { + match transaction { + Transaction::AccountTransaction(tx) => tx.fee_type(), + Transaction::L1HandlerTransaction(tx) => tx.fee_type(), + } +} + +pub fn to_blk_address(address: katana_primitives::contract::ContractAddress) -> ContractAddress { + ContractAddress(patricia_key!(address.0)) +} + +pub fn to_address(address: ContractAddress) -> katana_primitives::contract::ContractAddress { + katana_primitives::contract::ContractAddress((*address.0.key()).into()) +} + +pub fn to_blk_chain_id(chain_id: katana_primitives::chain::ChainId) -> ChainId { + match chain_id { + katana_primitives::chain::ChainId::Named(named) => ChainId(named.name().to_string()), + katana_primitives::chain::ChainId::Id(id) => { + let id = parse_cairo_short_string(&id).expect("valid cairo string"); + ChainId(id) + } + } +} + +pub fn to_class( + class: katana_primitives::class::CompiledClass, +) -> Result { + match class { + katana_primitives::class::CompiledClass::Deprecated(class) => { + Ok(ContractClass::V0(ContractClassV0::try_from(class)?)) + } + katana_primitives::class::CompiledClass::Class(class) => { + Ok(ContractClass::V1(ContractClassV1::try_from(class.casm)?)) + } + } +} + +/// TODO: remove this function once starknet api 0.8.0 is supported. +fn starknet_api_ethaddr_to_felt(value: starknet_api::core::EthAddress) -> FieldElement { + let mut bytes = [0u8; 32]; + // Padding H160 with zeros to 32 bytes (big endian) + bytes[12..32].copy_from_slice(value.0.as_bytes()); + let stark_felt = starknet_api::hash::StarkFelt::new(bytes).expect("valid slice for stark felt"); + stark_felt.into() +} + +pub fn to_exec_info(exec_info: TransactionExecutionInfo) -> TxExecInfo { + TxExecInfo { + validate_call_info: exec_info.validate_call_info.map(to_call_info), + execute_call_info: exec_info.execute_call_info.map(to_call_info), + fee_transfer_call_info: exec_info.fee_transfer_call_info.map(to_call_info), + actual_fee: exec_info.actual_fee.0, + actual_resources: exec_info + .actual_resources + .0 + .into_iter() + .map(|(k, v)| (k, v as u64)) + .collect(), + revert_error: exec_info.revert_error.clone(), + } +} + +fn to_call_info(call_info: CallInfo) -> katana_primitives::trace::CallInfo { + let message_to_l1_from_address = if let Some(a) = call_info.call.code_address { + to_address(a) + } else { + to_address(call_info.call.caller_address) + }; + + katana_primitives::trace::CallInfo { + contract_address: to_address(call_info.call.storage_address), + caller_address: to_address(call_info.call.caller_address), + call_type: match call_info.call.call_type { + CallType::Call => katana_primitives::trace::CallType::Call, + CallType::Delegate => katana_primitives::trace::CallType::Delegate, + }, + code_address: call_info.call.code_address.map(to_address), + class_hash: call_info.call.class_hash.map(|a| a.0.into()), + entry_point_selector: call_info.call.entry_point_selector.0.into(), + entry_point_type: match call_info.call.entry_point_type { + EntryPointType::External => katana_primitives::trace::EntryPointType::External, + EntryPointType::L1Handler => katana_primitives::trace::EntryPointType::L1Handler, + EntryPointType::Constructor => katana_primitives::trace::EntryPointType::Constructor, + }, + calldata: call_info.call.calldata.0.iter().map(|f| (*f).into()).collect(), + retdata: call_info.execution.retdata.0.iter().map(|f| (*f).into()).collect(), + execution_resources: katana_primitives::trace::ExecutionResources { + n_steps: call_info.vm_resources.n_steps as u64, + n_memory_holes: call_info.vm_resources.n_memory_holes as u64, + builtin_instance_counter: call_info + .vm_resources + .builtin_instance_counter + .into_iter() + .map(|(k, v)| (k, v as u64)) + .collect(), + }, + events: call_info + .execution + .events + .iter() + .map(|e| katana_primitives::event::OrderedEvent { + order: e.order as u64, + keys: e.event.keys.iter().map(|f| f.0.into()).collect(), + data: e.event.data.0.iter().map(|f| (*f).into()).collect(), + }) + .collect(), + l2_to_l1_messages: call_info + .execution + .l2_to_l1_messages + .iter() + .map(|m| { + let to_address = starknet_api_ethaddr_to_felt(m.message.to_address); + katana_primitives::message::OrderedL2ToL1Message { + order: m.order as u64, + from_address: message_to_l1_from_address, + to_address, + payload: m.message.payload.0.iter().map(|f| (*f).into()).collect(), + } + }) + .collect(), + storage_read_values: call_info.storage_read_values.into_iter().map(|f| f.into()).collect(), + accessed_storage_keys: call_info + .accessed_storage_keys + .into_iter() + .map(|sk| (*sk.0.key()).into()) + .collect(), + inner_calls: call_info.inner_calls.iter().map(|c| to_call_info(c.clone())).collect(), + gas_consumed: call_info.execution.gas_consumed as u128, + failed: call_info.execution.failed, + } +} + +#[cfg(test)] +mod tests { + use katana_primitives::chain::{ChainId, NamedChainId}; + use starknet::core::utils::parse_cairo_short_string; + + use crate::implementation::blockifier::utils::to_blk_chain_id; + + #[test] + fn convert_chain_id() { + let mainnet = to_blk_chain_id(ChainId::Named(NamedChainId::Mainnet)); + let goerli = to_blk_chain_id(ChainId::Named(NamedChainId::Goerli)); + let sepolia = to_blk_chain_id(ChainId::Named(NamedChainId::Sepolia)); + + assert_eq!(mainnet.0, parse_cairo_short_string(&NamedChainId::Mainnet.id()).unwrap()); + assert_eq!(goerli.0, parse_cairo_short_string(&NamedChainId::Goerli.id()).unwrap()); + assert_eq!(sepolia.0, parse_cairo_short_string(&NamedChainId::Sepolia.id()).unwrap()); + } +} diff --git a/crates/katana/executor/src/implementation/mod.rs b/crates/katana/executor/src/implementation/mod.rs new file mode 100644 index 0000000000..3e4f93f2b9 --- /dev/null +++ b/crates/katana/executor/src/implementation/mod.rs @@ -0,0 +1,7 @@ +#[cfg(feature = "blockifier")] +pub mod blockifier; + +#[cfg(feature = "sir")] +pub mod sir; + +pub mod noop; diff --git a/crates/katana/executor/src/implementation/noop.rs b/crates/katana/executor/src/implementation/noop.rs new file mode 100644 index 0000000000..3e6931b0ac --- /dev/null +++ b/crates/katana/executor/src/implementation/noop.rs @@ -0,0 +1,166 @@ +use katana_primitives::block::ExecutableBlock; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::transaction::{ExecutableTxWithHash, TxWithHash}; +use katana_primitives::FieldElement; +use katana_provider::traits::contract::ContractClassProvider; +use katana_provider::traits::state::StateProvider; +use katana_provider::ProviderResult; + +use crate::abstraction::{ + BlockExecutor, EntryPointCall, ExecutionOutput, ExecutionResult, ExecutorExt, ExecutorFactory, + ExecutorResult, ResultAndStates, SimulationFlag, +}; +use crate::ExecutionError; + +/// A no-op executor factory. Creates an executor that does nothing. +#[derive(Debug, Default)] +pub struct NoopExecutorFactory { + cfg: CfgEnv, +} + +impl NoopExecutorFactory { + /// Create a new no-op executor factory. + pub fn new() -> Self { + Self::default() + } +} + +impl ExecutorFactory for NoopExecutorFactory { + fn with_state<'a, P>(&self, state: P) -> Box + 'a> + where + P: StateProvider + 'a, + { + let _ = state; + Box::::default() + } + + fn with_state_and_block_env<'a, P>( + &self, + state: P, + block_env: BlockEnv, + ) -> Box + 'a> + where + P: StateProvider + 'a, + { + let _ = state; + let _ = block_env; + Box::new(NoopExecutor { block_env }) + } + + fn cfg(&self) -> &CfgEnv { + &self.cfg + } +} + +#[derive(Debug, Default)] +struct NoopExecutor { + block_env: BlockEnv, +} + +impl ExecutorExt for NoopExecutor { + fn simulate( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec { + let _ = transactions; + let _ = flags; + vec![] + } + + fn estimate_fee( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec> { + let _ = transactions; + let _ = flags; + vec![] + } + + fn call(&self, call: EntryPointCall) -> Result, ExecutionError> { + let _ = call; + Ok(vec![]) + } +} + +impl<'a> BlockExecutor<'a> for NoopExecutor { + fn execute_block(&mut self, block: ExecutableBlock) -> ExecutorResult<()> { + let _ = block; + Ok(()) + } + + fn execute_transactions( + &mut self, + transactions: Vec, + ) -> ExecutorResult<()> { + let _ = transactions; + Ok(()) + } + + fn take_execution_output(&mut self) -> ExecutorResult { + Ok(ExecutionOutput::default()) + } + + fn state(&self) -> Box { + Box::new(NoopStateProvider) + } + + fn transactions(&self) -> &[(TxWithHash, ExecutionResult)] { + &[] + } + + fn block_env(&self) -> BlockEnv { + self.block_env.clone() + } +} + +struct NoopStateProvider; + +impl ContractClassProvider for NoopStateProvider { + fn class(&self, hash: ClassHash) -> ProviderResult> { + let _ = hash; + Ok(None) + } + + fn compiled_class_hash_of_class_hash( + &self, + hash: ClassHash, + ) -> ProviderResult> { + let _ = hash; + Ok(None) + } + + fn sierra_class(&self, hash: ClassHash) -> ProviderResult> { + let _ = hash; + Ok(None) + } +} + +impl StateProvider for NoopStateProvider { + fn class_hash_of_contract( + &self, + address: ContractAddress, + ) -> ProviderResult> { + let _ = address; + Ok(None) + } + + fn nonce(&self, address: ContractAddress) -> ProviderResult> { + let _ = address; + Ok(None) + } + + fn storage( + &self, + address: ContractAddress, + storage_key: StorageKey, + ) -> ProviderResult> { + let _ = address; + let _ = storage_key; + Ok(None) + } +} diff --git a/crates/katana/executor/src/implementation/sir/error.rs b/crates/katana/executor/src/implementation/sir/error.rs new file mode 100644 index 0000000000..9808c04b8a --- /dev/null +++ b/crates/katana/executor/src/implementation/sir/error.rs @@ -0,0 +1,43 @@ +use katana_primitives::FieldElement; +use sir::transaction::error::TransactionError; + +use super::utils::{to_class_hash, to_felt}; +use crate::ExecutionError; + +impl From for ExecutionError { + fn from(error: TransactionError) -> Self { + match error { + TransactionError::ActualFeeExceedsMaxFee(actual_fee, max_fee) => { + Self::ActualFeeExceedsMaxFee { max_fee, actual_fee } + } + + TransactionError::ClassAlreadyDeclared(hash) => { + Self::ClassAlreadyDeclared(to_class_hash(&hash)) + } + + TransactionError::InvalidTransactionNonce(expected, actual) => { + let actual = FieldElement::from_dec_str(&actual).expect("must be valid"); + let expected = FieldElement::from_dec_str(&expected).expect("must be valid"); + Self::InvalidNonce { actual, expected } + } + + TransactionError::MaxFeeExceedsBalance(max_fee, low, high) => { + let balance_low = to_felt(&low); + let balance_high = to_felt(&high); + Self::InsufficientBalance { max_fee, balance_low, balance_high } + } + + TransactionError::NotDeployedContract(address) => { + let address = FieldElement::from_bytes_be(&address.0).expect("valid felt").into(); + Self::ContractNotDeployed(address) + } + + TransactionError::MaxFeeTooLow(max_fee, min) => Self::MaxFeeTooLow { max_fee, min }, + TransactionError::EntryPointNotFound(selector) => { + Self::EntryPointNotFound(to_felt(&selector)) + } + TransactionError::FeeTransferError(e) => Self::FeeTransferError(e.to_string()), + e => Self::Other(e.to_string()), + } + } +} diff --git a/crates/katana/executor/src/implementation/sir/mod.rs b/crates/katana/executor/src/implementation/sir/mod.rs new file mode 100644 index 0000000000..603219e89c --- /dev/null +++ b/crates/katana/executor/src/implementation/sir/mod.rs @@ -0,0 +1,269 @@ +mod error; +mod output; +mod state; +pub mod utils; + +use std::sync::Arc; + +use katana_primitives::block::{ExecutableBlock, PartialHeader}; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxWithHash}; +use katana_primitives::FieldElement; +use katana_provider::traits::state::StateProvider; +use sir::definitions::block_context::{self, BlockContext}; +use sir::execution::TransactionExecutionInfo; +use sir::state::cached_state; +use sir::state::contract_class_cache::PermanentContractClassCache; +use tracing::info; + +use self::output::receipt_from_exec_info; +use self::state::CachedState; +use crate::abstraction::{ + BlockExecutor, ExecutionOutput, ExecutorExt, ExecutorFactory, ExecutorResult, SimulationFlag, + StateProviderDb, +}; +use crate::{EntryPointCall, ExecutionError, ExecutionResult, ResultAndStates}; + +/// A factory for creating [StarknetVMProcessor] instances. +#[derive(Debug)] +pub struct NativeExecutorFactory { + cfg: CfgEnv, + flags: SimulationFlag, +} + +impl NativeExecutorFactory { + /// Create a new factory with the given configuration and simulation flags. + pub fn new(cfg: CfgEnv, flags: SimulationFlag) -> Self { + Self { cfg, flags } + } +} + +impl ExecutorFactory for NativeExecutorFactory { + fn with_state<'a, P>(&self, state: P) -> Box + 'a> + where + P: StateProvider + 'a, + { + self.with_state_and_block_env(state, BlockEnv::default()) + } + + fn with_state_and_block_env<'a, P>( + &self, + state: P, + block_env: BlockEnv, + ) -> Box + 'a> + where + P: StateProvider + 'a, + { + let cfg_env = self.cfg.clone(); + let simulation_flags = self.flags.clone(); + Box::new(StarknetVMProcessor::new(Box::new(state), block_env, cfg_env, simulation_flags)) + } + + fn cfg(&self) -> &CfgEnv { + &self.cfg + } +} + +pub struct StarknetVMProcessor<'a> { + block_context: BlockContext, + state: CachedState, PermanentContractClassCache>, + transactions: Vec<(TxWithHash, ExecutionResult)>, + simulation_flags: SimulationFlag, +} + +impl<'a> StarknetVMProcessor<'a> { + pub fn new( + state: Box, + block_env: BlockEnv, + cfg_env: CfgEnv, + simulation_flags: SimulationFlag, + ) -> Self { + let transactions = Vec::new(); + let block_context = utils::block_context_from_envs(&block_env, &cfg_env); + let state = + CachedState::new(StateProviderDb(state), PermanentContractClassCache::default()); + Self { block_context, state, transactions, simulation_flags } + } + + fn fill_block_env_from_header(&mut self, header: &PartialHeader) { + let number = header.number; + let timestamp = header.timestamp; + let sequencer_address = utils::to_sir_address(&header.sequencer_address); + + let gas_prices = block_context::GasPrices { + eth_l1_gas_price: header.gas_prices.eth, + strk_l1_gas_price: header.gas_prices.strk, + }; + + self.block_context.block_info_mut().block_number = number; + self.block_context.block_info_mut().gas_price = gas_prices; + self.block_context.block_info_mut().block_timestamp = timestamp; + self.block_context.block_info_mut().sequencer_address = sequencer_address; + } + + fn simulate_with( + &self, + transactions: Vec, + flags: &SimulationFlag, + mut op: F, + ) -> Vec + where + F: FnMut((TxWithHash, Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError>)) -> T, + { + let block_context = &self.block_context; + + let mut state = cached_state::CachedState::new( + Arc::new(&self.state), + Arc::new(PermanentContractClassCache::default()), + ); + + let mut results = Vec::with_capacity(transactions.len()); + for exec_tx in transactions { + let tx = TxWithHash::from(&exec_tx); + let res = utils::transact(exec_tx, &mut state, block_context, flags); + + results.push(op((tx, res))); + } + + results + } +} + +impl<'a> BlockExecutor<'a> for StarknetVMProcessor<'a> { + fn execute_transactions( + &mut self, + transactions: Vec, + ) -> ExecutorResult<()> { + let block_context = &self.block_context; + let flags = &self.simulation_flags; + let mut state = self.state.0.write(); + + for exec_tx in transactions { + // Collect class artifacts if its a declare tx + let class_decl_artifacts = if let ExecutableTx::Declare(tx) = exec_tx.as_ref() { + let class_hash = tx.class_hash(); + Some((class_hash, tx.compiled_class.clone(), tx.sierra_class.clone())) + } else { + None + }; + + let tx = TxWithHash::from(&exec_tx); + let res = match utils::transact(exec_tx, &mut state.inner, block_context, flags) { + Ok((info, fee)) => { + // get the trace and receipt from the execution info + let trace = utils::to_exec_info(&info); + let receipt = receipt_from_exec_info(&tx, &trace); + + crate::utils::log_resources(&trace.actual_resources); + crate::utils::log_events(receipt.events()); + + if let Some(reason) = receipt.revert_reason() { + info!(target: "executor", "transaction reverted: {reason}"); + } + + ExecutionResult::new_success(receipt, trace, fee) + } + Err(e) => { + info!(target: "executor", "transaction execution failed: {e}"); + ExecutionResult::new_failed(e) + } + }; + + // if the tx succeed, inserts the class artifacts into the contract class cache + if res.is_success() { + if let Some((class_hash, compiled, sierra)) = class_decl_artifacts { + state.declared_classes.insert(class_hash, (compiled, sierra)); + } + } + + self.transactions.push((tx, res)); + } + + Ok(()) + } + + fn execute_block(&mut self, block: ExecutableBlock) -> ExecutorResult<()> { + self.fill_block_env_from_header(&block.header); + self.execute_transactions(block.body)?; + Ok(()) + } + + fn take_execution_output(&mut self) -> ExecutorResult { + let states = utils::state_update_from_cached_state(&self.state); + let transactions = std::mem::take(&mut self.transactions); + Ok(ExecutionOutput { states, transactions }) + } + + fn state(&self) -> Box { + Box::new(self.state.clone()) + } + + fn transactions(&self) -> &[(TxWithHash, ExecutionResult)] { + &self.transactions + } + + fn block_env(&self) -> BlockEnv { + BlockEnv { + number: self.block_context.block_info().block_number, + timestamp: self.block_context.block_info().block_timestamp, + sequencer_address: utils::to_address( + &self.block_context.block_info().sequencer_address, + ), + l1_gas_prices: katana_primitives::block::GasPrices { + eth: self.block_context.block_info().gas_price.eth_l1_gas_price, + strk: self.block_context.block_info().gas_price.strk_l1_gas_price, + }, + } + } +} + +impl<'a> ExecutorExt for StarknetVMProcessor<'a> { + fn simulate( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec { + self.simulate_with(transactions, &flags, |(tx, res)| { + let result = match res { + Ok((info, fee)) => { + // get the trace and receipt from the execution info + let trace = utils::to_exec_info(&info); + let receipt = receipt_from_exec_info(&tx, &trace); + ExecutionResult::new_success(receipt, trace, fee) + } + Err(e) => ExecutionResult::new_failed(e), + }; + + ResultAndStates { result, states: Default::default() } + }) + } + + fn estimate_fee( + &self, + transactions: Vec, + flags: SimulationFlag, + ) -> Vec> { + self.simulate_with(transactions, &flags, |(_, res)| match res { + Ok((info, fee)) => { + // if the transaction was reverted, return as error + if let Some(reason) = info.revert_error { + info!(target: "executor", "fee estimation failed: {reason}"); + Err(ExecutionError::TransactionReverted { revert_error: reason }) + } else { + Ok(fee) + } + } + Err(e) => { + info!(target: "executor", "fee estimation failed: {e}"); + Err(e) + } + }) + } + + fn call(&self, call: EntryPointCall) -> Result, ExecutionError> { + let block_context = &self.block_context; + let retdata = utils::call(call, &self.state, block_context, 100_000_000)?; + Ok(retdata) + } +} diff --git a/crates/katana/executor/src/implementation/sir/output.rs b/crates/katana/executor/src/implementation/sir/output.rs new file mode 100644 index 0000000000..3e435c1b4f --- /dev/null +++ b/crates/katana/executor/src/implementation/sir/output.rs @@ -0,0 +1,153 @@ +use std::collections::HashMap; + +use katana_primitives::receipt::{ + DeclareTxReceipt, DeployAccountTxReceipt, Event, InvokeTxReceipt, L1HandlerTxReceipt, + MessageToL1, Receipt, TxExecutionResources, +}; +use katana_primitives::trace::{CallInfo, TxExecInfo}; +use katana_primitives::transaction::Tx; + +pub(super) fn receipt_from_exec_info(tx: &Tx, info: &TxExecInfo) -> Receipt { + let actual_fee = info.actual_fee; + let events = events_from_exec_info(info); + let revert_error = info.revert_error.clone(); + let messages_sent = l2_to_l1_messages_from_exec_info(info); + let actual_resources = parse_actual_resources(&info.actual_resources); + + match tx { + Tx::Invoke(_) => Receipt::Invoke(InvokeTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + }), + + Tx::Declare(_) => Receipt::Declare(DeclareTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + }), + + Tx::L1Handler(tx) => Receipt::L1Handler(L1HandlerTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + message_hash: tx.message_hash, + execution_resources: actual_resources, + }), + + Tx::DeployAccount(tx) => Receipt::DeployAccount(DeployAccountTxReceipt { + events, + actual_fee, + revert_error, + messages_sent, + execution_resources: actual_resources, + contract_address: tx.contract_address(), + }), + } +} + +fn events_from_exec_info(info: &TxExecInfo) -> Vec { + let mut events: Vec = vec![]; + + fn get_events_recursively(call_info: &CallInfo) -> Vec { + let mut events: Vec = vec![]; + + // By default, `from_address` must correspond to the contract address that + // is sending the message. In the case of library calls, `code_address` is `None`, + // we then use the `caller_address` instead (which can also be an account). + let from_address = if let Some(code_address) = call_info.code_address { + code_address + } else { + call_info.caller_address + }; + + events.extend(call_info.events.iter().map(|e| Event { + from_address, + data: e.data.clone(), + keys: e.keys.clone(), + })); + + call_info.inner_calls.iter().for_each(|call| { + events.extend(get_events_recursively(call)); + }); + + events + } + + if let Some(ref call) = info.validate_call_info { + events.extend(get_events_recursively(call)); + } + + if let Some(ref call) = info.execute_call_info { + events.extend(get_events_recursively(call)); + } + + if let Some(ref call) = info.fee_transfer_call_info { + events.extend(get_events_recursively(call)); + } + + events +} + +fn l2_to_l1_messages_from_exec_info(info: &TxExecInfo) -> Vec { + let mut messages = vec![]; + + fn get_messages_recursively(info: &CallInfo) -> Vec { + let mut messages = vec![]; + + // By default, `from_address` must correspond to the contract address that + // is sending the message. In the case of library calls, `code_address` is `None`, + // we then use the `caller_address` instead (which can also be an account). + let from_address = if let Some(code_address) = info.code_address { + code_address + } else { + info.caller_address + }; + + messages.extend(info.l2_to_l1_messages.iter().map(|m| MessageToL1 { + from_address, + to_address: m.to_address, + payload: m.payload.clone(), + })); + + info.inner_calls.iter().for_each(|call| { + messages.extend(get_messages_recursively(call)); + }); + + messages + } + + if let Some(ref info) = info.validate_call_info { + messages.extend(get_messages_recursively(info)); + } + + if let Some(ref info) = info.execute_call_info { + messages.extend(get_messages_recursively(info)); + } + + if let Some(ref info) = info.fee_transfer_call_info { + messages.extend(get_messages_recursively(info)); + } + + messages +} + +fn parse_actual_resources(resources: &HashMap) -> TxExecutionResources { + TxExecutionResources { + steps: resources.get("n_steps").copied().unwrap_or_default(), + memory_holes: resources.get("memory_holes").copied(), + ec_op_builtin: resources.get("ec_op_builtin").copied(), + ecdsa_builtin: resources.get("ecdsa_builtin").copied(), + keccak_builtin: resources.get("keccak_builtin").copied(), + bitwise_builtin: resources.get("bitwise_builtin").copied(), + pedersen_builtin: resources.get("pedersen_builtin").copied(), + poseidon_builtin: resources.get("poseidon_builtin").copied(), + range_check_builtin: resources.get("range_check_builtin").copied(), + segment_arena_builtin: resources.get("segment_arena_builtin").copied(), + } +} diff --git a/crates/katana/executor/src/implementation/sir/state.rs b/crates/katana/executor/src/implementation/sir/state.rs new file mode 100644 index 0000000000..74bd309692 --- /dev/null +++ b/crates/katana/executor/src/implementation/sir/state.rs @@ -0,0 +1,583 @@ +use std::collections::HashMap; +use std::sync::Arc; + +use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; +use katana_primitives::FieldElement; +use katana_provider::error::ProviderError; +use katana_provider::traits::contract::ContractClassProvider; +use katana_provider::traits::state::StateProvider; +use katana_provider::ProviderResult; +use parking_lot::RwLock; +use sir::core::errors::state_errors::StateError; +use sir::state::cached_state; +use sir::state::contract_class_cache::ContractClassCache; +use sir::state::state_api::StateReader; +use sir::state::state_cache::StorageEntry; +use sir::transaction::{Address, ClassHash, CompiledClassHash}; +use sir::Felt252; + +use super::utils; +use crate::abstraction::StateProviderDb; + +/// A helper trait to enforce that a type must implement both [StateProvider] and [StateReader]. +pub(super) trait StateDb: StateProvider + StateReader {} +impl StateDb for T where T: StateProvider + StateReader {} + +impl<'a> StateReader for StateProviderDb<'a> { + fn get_class_hash_at(&self, contract_address: &Address) -> Result { + match self.0.class_hash_of_contract(utils::to_address(contract_address)) { + Ok(Some(value)) => Ok(utils::to_sir_class_hash(&value)), + + Ok(None) => Ok(ClassHash::default()), + Err(e) => Err(StateError::CustomError(e.to_string())), + } + } + + fn get_compiled_class_hash( + &self, + class_hash: &ClassHash, + ) -> Result { + match self.0.compiled_class_hash_of_class_hash(utils::to_class_hash(class_hash)) { + Ok(Some(value)) => Ok(utils::to_sir_class_hash(&value)), + + Ok(None) => Err(StateError::NoneCompiledHash(*class_hash)), + Err(e) => Err(StateError::CustomError(e.to_string())), + } + } + + fn get_contract_class( + &self, + class_hash: &ClassHash, + ) -> Result + { + match self.0.class(utils::to_class_hash(class_hash)) { + Ok(Some(value)) => Ok(utils::to_sir_compiled_class(value)), + + Ok(None) => Err(StateError::NoneCompiledClass(*class_hash)), + Err(e) => Err(StateError::CustomError(e.to_string())), + } + } + + fn get_nonce_at(&self, contract_address: &Address) -> Result { + match self.0.nonce(utils::to_address(contract_address)) { + Ok(Some(value)) => Ok(utils::to_sir_felt(&value)), + + Ok(None) => Ok(Felt252::ZERO), + Err(e) => Err(StateError::CustomError(e.to_string())), + } + } + + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { + let address = utils::to_address(&storage_entry.0); + let key = FieldElement::from_bytes_be(&storage_entry.1).unwrap(); + + match self.0.storage(address, key) { + Ok(Some(value)) => Ok(utils::to_sir_felt(&value)), + + Ok(None) => Ok(Felt252::ZERO), + Err(e) => Err(StateError::CustomError(e.to_string())), + } + } +} + +type DeclaredClass = (CompiledClass, Option); + +#[derive(Debug, Default)] +pub(super) struct CachedState(pub(super) Arc>>) +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync; + +impl Clone for CachedState +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } +} + +#[derive(Debug, Default)] +pub(super) struct CachedStateInner +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + pub(super) inner: cached_state::CachedState, + pub(super) declared_classes: HashMap, +} + +impl CachedState +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + pub(super) fn new(state: S, classes_cache: C) -> Self { + let declared_classes = HashMap::new(); + let cached_state = cached_state::CachedState::new(Arc::new(state), Arc::new(classes_cache)); + let inner = CachedStateInner { inner: cached_state, declared_classes }; + Self(Arc::new(RwLock::new(inner))) + } +} + +impl ContractClassProvider for CachedState +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + fn class( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let state = self.0.read(); + if let Some((class, _)) = state.declared_classes.get(&hash) { + Ok(Some(class.clone())) + } else { + state.inner.state_reader.class(hash) + } + } + + fn compiled_class_hash_of_class_hash( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let state = self.0.read(); + let hash = utils::to_sir_class_hash(&hash); + + match state.inner.get_compiled_class_hash(&hash) { + Ok(value) => Ok(Some(utils::to_class_hash(&value))), + + Err(StateError::NoneCompiledHash(_)) => Ok(None), + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } + + fn sierra_class( + &self, + hash: katana_primitives::class::ClassHash, + ) -> ProviderResult> { + let state = self.0.read(); + if let Some((_, sierra)) = state.declared_classes.get(&hash) { + Ok(sierra.clone()) + } else { + state.inner.state_reader.sierra_class(hash) + } + } +} + +impl StateProvider for CachedState +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + fn class_hash_of_contract( + &self, + address: ContractAddress, + ) -> ProviderResult> { + let state = self.0.read(); + + let res = state + .inner + .get_class_hash_at(&utils::to_sir_address(&address)) + .map(|v| utils::to_class_hash(&v)); + + match res { + Ok(value) if value != FieldElement::ZERO => Ok(Some(value)), + // check the inner state provider if the class hash is not found in the + // cache state or if the returned class hash is zero + Ok(_) | Err(StateError::NoneClassHash(_)) => { + state.inner.state_reader.class_hash_of_contract(address) + } + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } + + fn nonce(&self, address: ContractAddress) -> ProviderResult> { + // check if the contract is deployed + if self.class_hash_of_contract(address)?.is_none() { + return Ok(None); + } + + let state = self.0.read(); + let address = utils::to_sir_address(&address); + + match state.inner.get_nonce_at(&address) { + Ok(value) => Ok(Some(utils::to_felt(&value))), + + Err(StateError::NoneNonce(_)) => Ok(None), + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } + + // This function will ONLY return `None` if the contract is not deployed + // and NOT if the contract is deployed but the storage is empty. Retrieving + // non-existant storage will return FieldElement::ZERO due to the nature of + // the StateReader trait. + fn storage( + &self, + address: ContractAddress, + storage_key: StorageKey, + ) -> ProviderResult> { + // check if the contract is deployed + if self.class_hash_of_contract(address)?.is_none() { + return Ok(None); + } + + let state = self.0.read(); + + let address = utils::to_sir_address(&address); + let key = utils::to_sir_felt(&storage_key); + + match state.inner.get_storage_at(&(address, key.to_bytes_be())) { + Ok(value) => Ok(Some(utils::to_felt(&value))), + + Err(StateError::NoneStorage(_)) => Ok(None), + Err(e) => Err(ProviderError::Other(e.to_string())), + } + } +} + +impl StateReader for CachedState +where + S: StateDb + Send + Sync, + C: ContractClassCache + Send + Sync, +{ + fn get_class_hash_at(&self, contract_address: &Address) -> Result { + self.0.read().inner.get_class_hash_at(contract_address) + } + + fn get_compiled_class_hash( + &self, + class_hash: &ClassHash, + ) -> Result { + self.0.read().inner.get_compiled_class_hash(class_hash) + } + + fn get_contract_class( + &self, + class_hash: &ClassHash, + ) -> Result + { + self.0.read().inner.get_contract_class(class_hash) + } + + fn get_nonce_at(&self, contract_address: &Address) -> Result { + self.0.read().inner.get_nonce_at(contract_address) + } + + fn get_storage_at(&self, storage_entry: &StorageEntry) -> Result { + self.0.read().inner.get_storage_at(storage_entry) + } +} + +#[cfg(test)] +mod tests { + + use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; + use katana_primitives::contract::ContractAddress; + use katana_primitives::genesis::constant::{ + DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, DEFAULT_OZ_ACCOUNT_CONTRACT, + DEFAULT_OZ_ACCOUNT_CONTRACT_CASM, + }; + use katana_primitives::utils::class::{parse_compiled_class, parse_sierra_class}; + use katana_primitives::FieldElement; + use katana_provider::providers::in_memory::InMemoryProvider; + use katana_provider::traits::contract::ContractClassWriter; + use katana_provider::traits::state::{StateFactoryProvider, StateProvider, StateWriter}; + use sir::state::contract_class_cache::PermanentContractClassCache; + use sir::state::state_api::{State, StateReader}; + use sir::transaction::ClassHash; + use sir::Felt252; + use starknet::macros::felt; + + use super::CachedState; + use crate::implementation::sir::utils::{ + to_sir_address, to_sir_class_hash, to_sir_compiled_class, to_sir_felt, + }; + use crate::StateProviderDb; + + fn new_sierra_class() -> (FlattenedSierraClass, CompiledClass) { + let json = include_str!("../../../../primitives/contracts/compiled/cairo1_contract.json"); + let artifact = serde_json::from_str(json).unwrap(); + let compiled_class = parse_compiled_class(artifact).unwrap(); + let sierra_class = parse_sierra_class(json).unwrap().flatten().unwrap(); + (sierra_class, compiled_class) + } + + fn state_provider() -> Box { + let address = ContractAddress::from(felt!("0x67")); + let nonce = felt!("0x7"); + let storage_key = felt!("0x1"); + let storage_value = felt!("0x2"); + let class_hash = felt!("0x123"); + let compiled_hash = felt!("0x456"); + let sierra_class = DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(); + let class = DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone(); + let legacy_class_hash = felt!("0x111"); + let legacy_class = DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone(); + + let provider = InMemoryProvider::new(); + provider.set_nonce(address, nonce).unwrap(); + provider.set_class_hash_of_contract(address, class_hash).unwrap(); + provider.set_storage(address, storage_key, storage_value).unwrap(); + provider.set_compiled_class_hash_of_class_hash(class_hash, compiled_hash).unwrap(); + provider.set_class(class_hash, class).unwrap(); + provider.set_sierra_class(class_hash, sierra_class).unwrap(); + provider.set_class(legacy_class_hash, legacy_class).unwrap(); + + provider.latest().unwrap() + } + + #[test] + fn can_fetch_from_inner_state_provider() -> anyhow::Result<()> { + let state = state_provider(); + let classes_cache = PermanentContractClassCache::default(); + let cached_state = CachedState::new(StateProviderDb(state), classes_cache); + + let address = to_sir_address(&ContractAddress::from(felt!("0x67"))); + let legacy_class_hash = to_sir_class_hash(&felt!("0x111")); + + let actual_class_hash = cached_state.get_class_hash_at(&address)?; + let actual_nonce = cached_state.get_nonce_at(&address)?; + let actual_storage_value = + cached_state.get_storage_at(&(address.clone(), felt!("0x1").to_bytes_be()))?; + let actual_compiled_hash = cached_state.get_compiled_class_hash(&actual_class_hash)?; + let actual_class = cached_state.get_contract_class(&actual_class_hash)?; + let actual_legacy_class = cached_state.get_contract_class(&legacy_class_hash)?; + + assert_eq!(actual_nonce, to_sir_felt(&felt!("0x7"))); + assert_eq!(actual_storage_value, to_sir_felt(&felt!("0x2"))); + assert_eq!(actual_class_hash, to_sir_class_hash(&felt!("0x123"))); + assert_eq!(actual_compiled_hash, to_sir_class_hash(&felt!("0x456"))); + assert_eq!(actual_class, to_sir_compiled_class(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone())); + assert_eq!( + actual_legacy_class, + to_sir_compiled_class(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone()) + ); + + Ok(()) + } + + #[test] + fn can_fetch_as_state_provider() -> anyhow::Result<()> { + let sp = state_provider(); + + // cache_state native data + let new_address = ContractAddress::from(felt!("0xdead")); + let new_storage_key = felt!("0xf00"); + let new_storage_value = felt!("0xba"); + let new_legacy_class_hash = felt!("0x1234"); + let new_legacy_class = DEFAULT_LEGACY_UDC_CASM.clone(); + let new_class_hash = felt!("0x777"); + let (new_sierra_class, new_compiled_sierra_class) = new_sierra_class(); + let new_compiled_hash = felt!("0xdead"); + // let new_legacy_compiled_hash = felt!("0x5678"); + + // we're asserting that the underlying state provider doesnt have cache state native data + + let actual_new_nonce = sp.nonce(new_address)?; + let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; + let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; + let actual_new_legacy_class = sp.class(new_legacy_class_hash)?; + let actual_new_legacy_sierra_class = sp.class(new_legacy_class_hash)?; + let actual_new_sierra_class = sp.sierra_class(new_class_hash)?; + let actual_new_class = sp.class(new_class_hash)?; + let actual_new_compiled_class_hash = + sp.compiled_class_hash_of_class_hash(new_class_hash)?; + let actual_new_legacy_compiled_hash = + sp.compiled_class_hash_of_class_hash(new_class_hash)?; + + assert_eq!(actual_new_nonce, None, "data shouldn't exist"); + assert_eq!(actual_new_class_hash, None, "data shouldn't exist"); + assert_eq!(actual_new_storage_value, None, "data shouldn't exist"); + assert_eq!(actual_new_legacy_class, None, "data should'nt exist"); + assert_eq!(actual_new_legacy_sierra_class, None, "data shouldn't exist"); + assert_eq!(actual_new_sierra_class, None, "data shouldn't exist"); + assert_eq!(actual_new_class, None, "data shouldn't exist"); + assert_eq!(actual_new_compiled_class_hash, None, "data shouldn't exist"); + assert_eq!(actual_new_legacy_compiled_hash, None, "data shouldn't exist"); + + let classes_cache = PermanentContractClassCache::default(); + let cached_state = CachedState::new(StateProviderDb(sp), classes_cache); + + // insert some data to the cached state + { + let sir_address = to_sir_address(&new_address); + let sir_legacy_class_hash = to_sir_class_hash(&new_legacy_class_hash); + // let sir_legacy_compiled_hash = to_sir_felt(&new_compiled_hash); + let sir_storage_key = new_storage_key.to_bytes_be(); + let sir_storage_value = to_sir_felt(&new_storage_value); + let sir_class_hash = to_sir_class_hash(&new_class_hash); + let sir_compiled_hash = to_sir_felt(&new_compiled_hash); + + let lock = &mut cached_state.0.write(); + let sir_state = &mut lock.inner; + + sir_state.increment_nonce(&sir_address)?; + sir_state.set_class_hash_at(sir_address.clone(), sir_legacy_class_hash)?; + sir_state.set_storage_at(&(sir_address.clone(), sir_storage_key), sir_storage_value); + sir_state.set_contract_class( + &sir_class_hash, + &to_sir_compiled_class(new_compiled_sierra_class.clone()), + )?; + sir_state.set_compiled_class_hash( + &Felt252::from_bytes_be(&sir_class_hash.0), + &sir_compiled_hash, + )?; + sir_state.set_contract_class( + &sir_legacy_class_hash, + &to_sir_compiled_class(DEFAULT_LEGACY_UDC_CASM.clone()), + )?; + + let declared_classes = &mut lock.declared_classes; + declared_classes.insert(new_legacy_class_hash, (new_legacy_class.clone(), None)); + declared_classes.insert( + new_class_hash, + (new_compiled_sierra_class.clone(), Some(new_sierra_class.clone())), + ); + } + + // assert that can fetch data from the underlyign state provider + let sp: Box = Box::new(cached_state); + + let address = ContractAddress::from(felt!("0x67")); + let class_hash = felt!("0x123"); + let legacy_class_hash = felt!("0x111"); + + let actual_class_hash = sp.class_hash_of_contract(address)?; + let actual_nonce = sp.nonce(address)?; + let actual_storage_value = sp.storage(address, felt!("0x1"))?; + let actual_class = sp.class(class_hash)?; + let actual_sierra_class = sp.sierra_class(class_hash)?; + let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; + let actual_legacy_class = sp.class(legacy_class_hash)?; + + assert_eq!(actual_nonce, Some(felt!("0x7"))); + assert_eq!(actual_class_hash, Some(class_hash)); + assert_eq!(actual_storage_value, Some(felt!("0x2"))); + assert_eq!(actual_compiled_hash, Some(felt!("0x456"))); + assert_eq!(actual_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT_CASM.clone())); + assert_eq!(actual_sierra_class, Some(DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten()?)); + assert_eq!(actual_legacy_class, Some(DEFAULT_LEGACY_ERC20_CONTRACT_CASM.clone())); + + // assert that can fetch data native to the cached state from the state provider + + let actual_new_class_hash = sp.class_hash_of_contract(new_address)?; + let actual_new_nonce = sp.nonce(new_address)?; + let actual_new_storage_value = sp.storage(new_address, new_storage_key)?; + let actual_new_class = sp.class(new_class_hash)?; + let actual_new_sierra = sp.sierra_class(new_class_hash)?; + let actual_new_compiled_hash = sp.compiled_class_hash_of_class_hash(new_class_hash)?; + let actual_legacy_class = sp.class(new_legacy_class_hash)?; + let actual_legacy_sierra = sp.sierra_class(new_legacy_class_hash)?; + // let actual_new_legacy_compiled_hash = + // sp.compiled_class_hash_of_class_hash(new_legacy_class_hash)?; + + assert_eq!(actual_new_nonce, Some(felt!("0x1")), "data should be in cached state"); + assert_eq!( + actual_new_class_hash, + Some(new_legacy_class_hash), + "data should be in cached state" + ); + assert_eq!( + actual_new_storage_value, + Some(new_storage_value), + "data should be in cached state" + ); + assert_eq!(actual_new_class, Some(new_compiled_sierra_class)); + assert_eq!(actual_new_sierra, Some(new_sierra_class)); + assert_eq!(actual_new_compiled_hash, Some(new_compiled_hash)); + assert_eq!(actual_legacy_class, Some(new_legacy_class)); + assert_eq!(actual_legacy_sierra, None, "legacy class should not have sierra class"); + + Ok(()) + } + + #[test] + fn fetch_non_existant_data() -> anyhow::Result<()> { + let db = InMemoryProvider::new(); + + let address = ContractAddress::from(felt!("0x1")); + let class_hash = felt!("0x123"); + let storage_key = felt!("0x1"); + + // edge case: the StateProvider::storage impl of CachedState will return + // default value for non-existant storage key of an existant contract. It will + // only return None if the contract does not exist. The intended behaviour for + // StateProvider::storage is to return None if the storage key or contract address + // does not exist. + let edge_address = ContractAddress::from(felt!("0x2")); + db.set_class_hash_of_contract(edge_address, class_hash)?; + + let sp = db.latest()?; + + let classes_cache = PermanentContractClassCache::default(); + let cached_state = CachedState::new(StateProviderDb(sp), classes_cache); + + let actual_nonce = cached_state + .get_nonce_at(&to_sir_address(&address)) + .expect("should return default value"); + let actual_storage_value = cached_state + .get_storage_at(&(to_sir_address(&address), storage_key.to_bytes_be())) + .expect("should return default value"); + let actual_class_hash = cached_state + .get_class_hash_at(&to_sir_address(&address)) + .expect("should return default value"); + let actual_compiled_hash = + cached_state.get_compiled_class_hash(&to_sir_class_hash(&class_hash)); + let actual_compiled_class = + cached_state.get_contract_class(&to_sir_class_hash(&class_hash)); + let actual_edge_storage_value = cached_state + .get_storage_at(&(to_sir_address(&edge_address), storage_key.to_bytes_be())) + .expect("should return default value"); + + assert_eq!( + actual_nonce, + Felt252::ZERO, + "nonce of nonexistant contract should default to zero" + ); + assert_eq!( + actual_storage_value, + Felt252::ZERO, + "value of nonexistant contract and storage key should default to zero" + ); + assert_eq!( + actual_edge_storage_value, + Felt252::ZERO, + "value of nonexistant storage key but existant contract should default to zero" + ); + assert_eq!( + actual_class_hash, + ClassHash::default(), + "class hash of nonexistant contract should default to zero" + ); + assert!( + actual_compiled_hash.unwrap_err().to_string().contains("No compiled class hash found") + ); + assert!(actual_compiled_class.unwrap_err().to_string().contains("No compiled class found")); + + let sp: Box = Box::new(cached_state); + + let actual_nonce = sp.nonce(address)?; + let actual_storage_value = sp.storage(address, storage_key)?; + let actual_edge_storage_value = sp.storage(edge_address, storage_key)?; + let actual_class_hash = sp.class_hash_of_contract(address)?; + let actual_compiled_hash = sp.compiled_class_hash_of_class_hash(class_hash)?; + let actual_class = sp.class(class_hash)?; + + assert_eq!(actual_nonce, None, "nonce of nonexistant contract should be None"); + assert_eq!(actual_class_hash, None, "class hash of nonexistant contract should be None"); + assert_eq!(actual_storage_value, None, "value of nonexistant contract should be None"); + assert_eq!( + actual_edge_storage_value, + Some(FieldElement::ZERO), + "edge case: value of nonexistant storage key but existant contract should return zero" + ); + assert_eq!(actual_compiled_hash, None); + assert_eq!(actual_class, None); + + Ok(()) + } +} diff --git a/crates/katana/executor/src/implementation/sir/utils.rs b/crates/katana/executor/src/implementation/sir/utils.rs new file mode 100644 index 0000000000..9b296ac68f --- /dev/null +++ b/crates/katana/executor/src/implementation/sir/utils.rs @@ -0,0 +1,731 @@ +use std::collections::HashMap; +use std::str::FromStr; +use std::sync::Arc; + +use katana_primitives::class::{CompiledClass, CompiledClassHash, DeprecatedCompiledClass}; +use katana_primitives::contract::{ContractAddress, StorageKey, StorageValue}; +use katana_primitives::env::{BlockEnv, CfgEnv}; +use katana_primitives::fee::TxFeeInfo; +use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; +use katana_primitives::transaction::{ + DeployAccountTx, ExecutableTx, ExecutableTxWithHash, InvokeTx, +}; +use katana_primitives::FieldElement; +use sir::definitions::block_context::{ + BlockContext, FeeTokenAddresses, FeeType, GasPrices, StarknetOsConfig, +}; +use sir::definitions::constants::TRANSACTION_VERSION; +use sir::execution::execution_entry_point::ExecutionEntryPoint; +use sir::execution::{CallInfo, CallType, TransactionExecutionContext, TransactionExecutionInfo}; +use sir::services::api::contract_classes::compiled_class::CompiledClass as SirCompiledClass; +use sir::services::api::contract_classes::deprecated_contract_class::ContractClass as SirDeprecatedContractClass; +use sir::state::contract_class_cache::{ContractClassCache, PermanentContractClassCache}; +use sir::state::state_api::StateReader; +use sir::state::state_cache::StateCache; +use sir::state::{cached_state, BlockInfo, ExecutionResourcesManager, StateDiff}; +use sir::transaction::error::TransactionError; +use sir::transaction::fee::{calculate_tx_fee, calculate_tx_l1_gas_usage}; +use sir::transaction::{ + Address, ClassHash, CurrentAccountTxFields, DataAvailabilityMode, Declare, DeclareDeprecated, + DeployAccount, InvokeFunction, L1Handler, ResourceBounds, Transaction, + VersionSpecificAccountTxFields, +}; +use sir::utils::calculate_sn_keccak; +use sir::EntryPointType; +use starknet::core::types::PriceUnit; +use starknet_types_core::felt::Felt; + +use super::state::{CachedState, StateDb}; +use super::SimulationFlag; +use crate::{EntryPointCall, ExecutionError}; + +pub(super) fn transact( + tx: ExecutableTxWithHash, + state: &mut cached_state::CachedState, + block_context: &BlockContext, + simulation_flag: &SimulationFlag, +) -> Result<(TransactionExecutionInfo, TxFeeInfo), ExecutionError> +where + S: StateReader, + C: ContractClassCache, +{ + let tx = to_executor_tx(tx, simulation_flag)?; + let fee_type = tx.fee_type(); + + let info = tx.execute( + state, + block_context, + u128::MAX, // TODO: this should be set as part of the transaction fee + #[cfg(feature = "native")] + None, + )?; + + // There are a few case where the `actual_fee` field of the transaction info is not set where + // the fee is skipped and thus not charged for the transaction (e.g. when the + // `skip_fee_transfer` is explicitly set, or when the transaction `max_fee` is set to 0). In + // these cases, we still want to calculate the fee. + let overall_fee = if info.actual_fee == 0 { + calculate_tx_fee(&info.actual_resources, block_context, &fee_type)? + } else { + info.actual_fee + }; + + let gas_consumed = calculate_tx_l1_gas_usage(&info.actual_resources, block_context)?; + let (unit, gas_price) = match fee_type { + FeeType::Eth => (PriceUnit::Wei, block_context.get_gas_price_by_fee_type(&FeeType::Eth)), + FeeType::Strk => (PriceUnit::Fri, block_context.get_gas_price_by_fee_type(&FeeType::Strk)), + }; + let fee = TxFeeInfo { gas_consumed, gas_price, unit, overall_fee }; + + Ok((info, fee)) +} + +pub fn call( + request: EntryPointCall, + state: impl StateReader, + block_context: &BlockContext, + initial_gas: u128, +) -> Result, ExecutionError> { + let mut state = cached_state::CachedState::new( + Arc::new(state), + Arc::new(PermanentContractClassCache::default()), + ); + + let contract_address = to_sir_address(&request.contract_address); + let entry_point_selector = to_sir_felt(&request.entry_point_selector); + let calldata = request.calldata.iter().map(to_sir_felt).collect::>(); + let call_type = Some(CallType::Call); + let caller_address = Address::default(); + let entry_point_type = EntryPointType::External; + + let call = ExecutionEntryPoint::new( + contract_address, + calldata, + entry_point_selector, + caller_address, + entry_point_type, + call_type, + None, + initial_gas, + ); + + let max_steps = block_context.invoke_tx_max_n_steps(); + let mut resources_manager = ExecutionResourcesManager::default(); + let mut tx_execution_context = TransactionExecutionContext::new( + Address::default(), + Felt::default(), + Vec::new(), + Default::default(), + Felt::default(), + block_context.invoke_tx_max_n_steps(), + *TRANSACTION_VERSION, + ); + + let result = call.execute( + &mut state, + block_context, + &mut resources_manager, + &mut tx_execution_context, + false, + max_steps, + #[cfg(feature = "native")] + None, + )?; + + let info = result.call_info.expect("should exist in call result"); + let retdata = info.retdata.iter().map(to_felt).collect(); + + Ok(retdata) +} + +fn to_executor_tx( + katana_tx: ExecutableTxWithHash, + simulation_flag: &SimulationFlag, +) -> Result { + match katana_tx.transaction { + ExecutableTx::Invoke(tx) => match tx { + InvokeTx::V1(tx) => { + let version = Felt::ONE; + let contract_address = to_sir_address(&tx.sender_address); + let entry_point = Felt::from_bytes_be(&calculate_sn_keccak(b"__execute__")); + let ver_specifc_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); + let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = Some(to_sir_felt(&tx.nonce)); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let tx = InvokeFunction::new_with_tx_hash( + contract_address, + entry_point, + ver_specifc_fields, + version, + calldata, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + + InvokeTx::V3(tx) => { + let version = Felt::THREE; + let contract_address = to_sir_address(&tx.sender_address); + let entry_point = Felt::from_bytes_be(&calculate_sn_keccak(b"__execute__")); + + let ver_specifc_fields = to_sir_current_account_tx_fields( + tx.tip, + tx.resource_bounds.l1_gas, + tx.resource_bounds.l2_gas, + tx.nonce_data_availability_mode, + tx.fee_data_availability_mode, + tx.paymaster_data, + tx.account_deployment_data, + ); + + let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = Some(to_sir_felt(&tx.nonce)); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let tx = InvokeFunction::new_with_tx_hash( + contract_address, + entry_point, + ver_specifc_fields, + version, + calldata, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + }, + + ExecutableTx::DeployAccount(tx) => match tx { + DeployAccountTx::V1(tx) => { + let version = Felt::ONE; + let class_hash = to_sir_class_hash(&tx.class_hash); + let ver_specifc_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); + let calldata = tx.constructor_calldata.iter().map(to_sir_felt).collect(); + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let tx = DeployAccount::new_with_tx_hash( + class_hash, + ver_specifc_fields, + version, + nonce, + calldata, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + + DeployAccountTx::V3(tx) => { + let version = Felt::THREE; + + let class_hash = to_sir_class_hash(&tx.class_hash); + let ver_specifc_fields = to_sir_current_account_tx_fields( + tx.tip, + tx.resource_bounds.l1_gas, + tx.resource_bounds.l2_gas, + tx.nonce_data_availability_mode, + tx.fee_data_availability_mode, + tx.paymaster_data, + vec![], + ); + let calldata = tx.constructor_calldata.iter().map(to_sir_felt).collect(); + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let tx = DeployAccount::new_with_tx_hash( + class_hash, + ver_specifc_fields, + version, + nonce, + calldata, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + }, + + ExecutableTx::Declare(declare) => match declare.transaction { + katana_primitives::transaction::DeclareTx::V1(tx) => { + let sender_address = to_sir_address(&tx.sender_address); + let max_fee = tx.max_fee; + let version = Felt::ONE; + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let tx_hash = to_sir_felt(&katana_tx.hash); + let class_hash = to_sir_class_hash(&tx.class_hash); + + let CompiledClass::Deprecated(class) = declare.compiled_class else { panic!() }; + let contract_class = to_sir_deprecated_class(class.clone()); + + let tx = DeclareDeprecated::new_with_tx_and_class_hash( + contract_class, + sender_address, + max_fee, + version, + signature, + nonce, + tx_hash, + class_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + + katana_primitives::transaction::DeclareTx::V2(tx) => { + let sierra_contract_class = None; + let sierra_class_hash = to_sir_felt(&tx.class_hash); + let compiled_class_hash = to_sir_felt(&tx.compiled_class_hash); + let sender_address = to_sir_address(&tx.sender_address); + let account_tx_fields = VersionSpecificAccountTxFields::Deprecated(tx.max_fee); + let version = Felt::TWO; + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let CompiledClass::Class(class) = declare.compiled_class else { panic!() }; + let casm_contract_class = Some(class.casm.clone()); + + let tx = Declare::new_with_sierra_class_hash_and_tx_hash( + sierra_contract_class, + sierra_class_hash, + casm_contract_class, + compiled_class_hash, + sender_address, + account_tx_fields, + version, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + + katana_primitives::transaction::DeclareTx::V3(tx) => { + let sierra_contract_class = None; + let sierra_class_hash = to_sir_felt(&tx.class_hash); + let compiled_class_hash = to_sir_felt(&tx.compiled_class_hash); + let sender_address = to_sir_address(&tx.sender_address); + let ver_specifc_fields = to_sir_current_account_tx_fields( + tx.tip, + tx.resource_bounds.l1_gas, + tx.resource_bounds.l2_gas, + tx.nonce_data_availability_mode, + tx.fee_data_availability_mode, + tx.paymaster_data, + tx.account_deployment_data, + ); + let version = Felt::THREE; + let signature = tx.signature.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let CompiledClass::Class(class) = declare.compiled_class else { panic!() }; + let casm_contract_class = Some(class.casm.clone()); + + let tx = Declare::new_with_sierra_class_hash_and_tx_hash( + sierra_contract_class, + sierra_class_hash, + casm_contract_class, + compiled_class_hash, + sender_address, + ver_specifc_fields, + version, + signature, + nonce, + tx_hash, + )?; + + let tx = tx.create_for_simulation( + simulation_flag.skip_validate, + simulation_flag.skip_execute, + simulation_flag.skip_fee_transfer, + simulation_flag.ignore_max_fee, + simulation_flag.skip_nonce_check, + ); + + Ok(tx) + } + }, + + ExecutableTx::L1Handler(tx) => { + let contract_address = to_sir_address(&tx.contract_address); + let entry_point = to_sir_felt(&tx.entry_point_selector); + let calldata = tx.calldata.iter().map(to_sir_felt).collect::>(); + let nonce = to_sir_felt(&tx.nonce); + let paid_fee_on_l1 = Some(Felt::from(tx.paid_fee_on_l1)); + let tx_hash = to_sir_felt(&katana_tx.hash); + + let tx = L1Handler::new_with_tx_hash( + contract_address, + entry_point, + calldata, + nonce, + paid_fee_on_l1, + tx_hash, + )?; + + let tx = tx + .create_for_simulation(simulation_flag.skip_validate, simulation_flag.skip_execute); + + Ok(tx) + } + } +} + +fn state_diff_from_state_cache(mut cache: StateCache) -> StateDiff { + let address_to_class_hash = std::mem::take(cache.class_hash_writes_mut()); + let address_to_nonce = std::mem::take(cache.nonce_writes_mut()); + let class_hash_to_compiled_class = std::mem::take(cache.compiled_class_hash_writes_mut()); + let storage_updates = sir::utils::to_state_diff_storage_mapping(cache.storage_writes()); + + StateDiff::new( + address_to_class_hash, + address_to_nonce, + class_hash_to_compiled_class, + storage_updates, + ) +} + +pub(super) fn to_felt(value: &Felt) -> FieldElement { + FieldElement::from_bytes_be(&value.to_bytes_be()).unwrap() +} + +pub(super) fn to_sir_felt(value: &FieldElement) -> Felt { + Felt::from_bytes_be(&value.to_bytes_be()) +} + +pub(super) fn to_address(value: &Address) -> ContractAddress { + ContractAddress::new(FieldElement::from_bytes_be(&value.0.to_bytes_be()).unwrap()) +} + +pub(super) fn to_sir_address(value: &ContractAddress) -> Address { + Address(to_sir_felt(&value.0)) +} + +pub(super) fn to_class_hash(value: &ClassHash) -> katana_primitives::class::ClassHash { + FieldElement::from_bytes_be(&value.0).unwrap() +} + +pub(super) fn to_sir_class_hash(value: &katana_primitives::class::ClassHash) -> ClassHash { + ClassHash(value.to_bytes_be()) +} + +pub(super) fn to_sir_compiled_class(class: CompiledClass) -> SirCompiledClass { + match class { + CompiledClass::Class(class) => { + let casm = Arc::new(class.casm); + let sierra = Some(Arc::new((class.sierra.program, class.sierra.entry_points_by_type))); + SirCompiledClass::Casm { casm, sierra } + } + + CompiledClass::Deprecated(class) => { + let class = Arc::new(to_sir_deprecated_class(class)); + SirCompiledClass::Deprecated(class) + } + } +} + +pub(super) fn to_sir_deprecated_class( + class: DeprecatedCompiledClass, +) -> SirDeprecatedContractClass { + let json = serde_json::to_string(&class).unwrap(); + SirDeprecatedContractClass::from_str(&json).unwrap() +} + +fn to_sir_current_account_tx_fields( + tip: u64, + l1_gas_resource_bounds: starknet::core::types::ResourceBounds, + l2_gas_resource_bounds: starknet::core::types::ResourceBounds, + nonce_data_availability_mode: starknet::core::types::DataAvailabilityMode, + fee_data_availability_mode: starknet::core::types::DataAvailabilityMode, + paymaster_data: Vec, + account_deployment_data: Vec, +) -> VersionSpecificAccountTxFields { + fn to_sir_da_mode(mode: starknet::core::types::DataAvailabilityMode) -> DataAvailabilityMode { + match mode { + starknet::core::types::DataAvailabilityMode::L1 => DataAvailabilityMode::L1, + starknet::core::types::DataAvailabilityMode::L2 => DataAvailabilityMode::L2, + } + } + + fn to_sir_resource_bounds( + resource_bounds: starknet::core::types::ResourceBounds, + ) -> ResourceBounds { + ResourceBounds { + max_amount: resource_bounds.max_amount, + max_price_per_unit: resource_bounds.max_price_per_unit, + } + } + + let l1_resource_bounds = to_sir_resource_bounds(l1_gas_resource_bounds); + let l2_resource_bounds = Some(to_sir_resource_bounds(l2_gas_resource_bounds)); + let nonce_data_availability_mode = to_sir_da_mode(nonce_data_availability_mode); + let fee_data_availability_mode = to_sir_da_mode(fee_data_availability_mode); + let paymaster_data = paymaster_data.iter().map(to_sir_felt).collect::>(); + let account_deployment_data = + account_deployment_data.iter().map(to_sir_felt).collect::>(); + + VersionSpecificAccountTxFields::Current(CurrentAccountTxFields { + tip, + paymaster_data, + l1_resource_bounds, + l2_resource_bounds, + account_deployment_data, + fee_data_availability_mode, + nonce_data_availability_mode, + }) +} + +pub fn to_exec_info(exec_info: &TransactionExecutionInfo) -> TxExecInfo { + TxExecInfo { + validate_call_info: exec_info.validate_info.clone().map(from_sir_call_info), + execute_call_info: exec_info.call_info.clone().map(from_sir_call_info), + fee_transfer_call_info: exec_info.fee_transfer_info.clone().map(from_sir_call_info), + actual_fee: exec_info.actual_fee, + actual_resources: exec_info + .actual_resources + .clone() + .into_iter() + .map(|(k, v)| (k, v as u64)) + .collect(), + revert_error: exec_info.revert_error.clone(), + // exec_info.tx_type being dropped here. + } +} + +fn from_sir_call_info(call_info: CallInfo) -> katana_primitives::trace::CallInfo { + let message_to_l1_from_address = if let Some(ref a) = call_info.code_address { + to_address(a) + } else { + to_address(&call_info.caller_address) + }; + + katana_primitives::trace::CallInfo { + contract_address: to_address(&call_info.contract_address), + caller_address: to_address(&call_info.caller_address), + call_type: match call_info.call_type { + Some(CallType::Call) => katana_primitives::trace::CallType::Call, + Some(CallType::Delegate) => katana_primitives::trace::CallType::Delegate, + _ => panic!("CallType is expected"), + }, + code_address: call_info.code_address.as_ref().map(to_address), + class_hash: call_info.class_hash.as_ref().map(to_class_hash), + entry_point_selector: to_felt( + &call_info.entry_point_selector.expect("EntryPointSelector is expected"), + ), + entry_point_type: match call_info.entry_point_type { + Some(EntryPointType::External) => katana_primitives::trace::EntryPointType::External, + Some(EntryPointType::L1Handler) => katana_primitives::trace::EntryPointType::L1Handler, + Some(EntryPointType::Constructor) => { + katana_primitives::trace::EntryPointType::Constructor + } + _ => panic!("EntryPointType is expected"), + }, + calldata: call_info.calldata.iter().map(to_felt).collect(), + retdata: call_info.retdata.iter().map(to_felt).collect(), + execution_resources: if let Some(ei) = call_info.execution_resources { + katana_primitives::trace::ExecutionResources { + n_steps: ei.n_steps as u64, + n_memory_holes: ei.n_memory_holes as u64, + builtin_instance_counter: ei + .builtin_instance_counter + .into_iter() + .map(|(k, v)| (k, v as u64)) + .collect(), + } + } else { + katana_primitives::trace::ExecutionResources::default() + }, + events: call_info + .events + .iter() + .map(|e| katana_primitives::event::OrderedEvent { + order: e.order, + keys: e.keys.iter().map(to_felt).collect(), + data: e.data.iter().map(to_felt).collect(), + }) + .collect(), + l2_to_l1_messages: call_info + .l2_to_l1_messages + .iter() + .map(|m| katana_primitives::message::OrderedL2ToL1Message { + order: m.order as u64, + from_address: message_to_l1_from_address, + to_address: *to_address(&m.to_address), + payload: m.payload.iter().map(to_felt).collect(), + }) + .collect(), + storage_read_values: call_info + .storage_read_values + .into_iter() + .map(|f| to_felt(&f)) + .collect(), + accessed_storage_keys: call_info.accessed_storage_keys.iter().map(to_class_hash).collect(), + inner_calls: call_info + .internal_calls + .iter() + .map(|c| from_sir_call_info(c.clone())) + .collect(), + gas_consumed: call_info.gas_consumed, + failed: call_info.failure_flag, + } +} + +pub(super) fn block_context_from_envs(block_env: &BlockEnv, cfg_env: &CfgEnv) -> BlockContext { + let chain_id = to_sir_felt(&cfg_env.chain_id.id()); + let fee_token_addreses = FeeTokenAddresses::new( + to_sir_address(&cfg_env.fee_token_addresses.eth), + to_sir_address(&cfg_env.fee_token_addresses.strk), + ); + + let gas_price = GasPrices { + eth_l1_gas_price: block_env.l1_gas_prices.eth, + strk_l1_gas_price: block_env.l1_gas_prices.strk, + }; + + let block_info = BlockInfo { + gas_price, + block_number: block_env.number, + block_timestamp: block_env.timestamp, + sequencer_address: to_sir_address(&block_env.sequencer_address), + }; + + BlockContext::new( + StarknetOsConfig::new(chain_id, fee_token_addreses), + Default::default(), + Default::default(), + cfg_env.vm_resource_fee_cost.clone(), + cfg_env.invoke_tx_max_n_steps as u64, + cfg_env.validate_max_n_steps as u64, + block_info, + Default::default(), + false, + ) +} +pub(super) fn state_update_from_cached_state( + state: &CachedState, +) -> StateUpdatesWithDeclaredClasses +where + S: StateDb, + C: ContractClassCache + Send + Sync, +{ + use katana_primitives::class::ClassHash; + + let state = &mut state.0.write(); + let state_changes = std::mem::take(state.inner.cache_mut()); + let state_diffs = state_diff_from_state_cache(state_changes); + let compiled_classes = std::mem::take(&mut state.declared_classes); + + let nonce_updates: HashMap = + state_diffs.address_to_nonce().iter().map(|(k, v)| (to_address(k), to_felt(v))).collect(); + + let declared_classes: HashMap = state_diffs + .class_hash_to_compiled_class() + .iter() + .map(|(k, v)| (to_class_hash(k), to_class_hash(v))) + .collect(); + + let contract_updates: HashMap = state_diffs + .address_to_class_hash() + .iter() + .map(|(k, v)| (to_address(k), to_class_hash(v))) + .collect(); + + let storage_updates: HashMap> = state_diffs + .storage_updates() + .iter() + .map(|(k, v)| { + let k = to_address(k); + let v = v.iter().map(|(k, v)| (to_felt(k), to_felt(v))).collect(); + (k, v) + }) + .collect(); + + let total_classes = declared_classes.len(); + let mut declared_compiled_classes = HashMap::with_capacity(total_classes); + let mut declared_sierra_classes = HashMap::with_capacity(total_classes); + + for (hash, (compiled, sierra)) in compiled_classes { + declared_compiled_classes.insert(hash, compiled); + if let Some(sierra) = sierra { + declared_sierra_classes.insert(hash, sierra); + } + } + + StateUpdatesWithDeclaredClasses { + declared_sierra_classes, + declared_compiled_classes, + state_updates: StateUpdates { + nonce_updates, + storage_updates, + contract_updates, + declared_classes, + }, + } +} diff --git a/crates/katana/executor/src/lib.rs b/crates/katana/executor/src/lib.rs index 22486ef41d..58b15c5484 100644 --- a/crates/katana/executor/src/lib.rs +++ b/crates/katana/executor/src/lib.rs @@ -1 +1,5 @@ -pub mod blockifier; +pub mod implementation; +mod utils; + +mod abstraction; +pub use abstraction::*; diff --git a/crates/katana/executor/src/utils.rs b/crates/katana/executor/src/utils.rs new file mode 100644 index 0000000000..6de7b60b33 --- /dev/null +++ b/crates/katana/executor/src/utils.rs @@ -0,0 +1,41 @@ +use std::collections::HashMap; + +use convert_case::{Case, Casing}; +use katana_primitives::receipt::Event; +use tracing::trace; + +pub fn log_resources(resources: &HashMap) { + let mut mapped_strings = resources + .iter() + .filter_map(|(k, v)| match k.as_str() { + "n_steps" => None, + "ecdsa_builtin" => Some(format!("ECDSA: {v}")), + "l1_gas_usage" => Some(format!("L1 Gas: {v}")), + "keccak_builtin" => Some(format!("Keccak: {v}")), + "bitwise_builtin" => Some(format!("Bitwise: {v}")), + "pedersen_builtin" => Some(format!("Pedersen: {v}")), + "range_check_builtin" => Some(format!("Range Checks: {v}")), + _ => Some(format!("{}: {}", k.to_case(Case::Title), v)), + }) + .collect::>(); + + // Sort the strings alphabetically + mapped_strings.sort(); + + // Prepend "Steps" if it exists, so it is always first + if let Some(steps) = resources.get("n_steps") { + mapped_strings.insert(0, format!("Steps: {}", steps)); + } + + trace!(target: "executor", "transaction resource usage: {}", mapped_strings.join(" | ")); +} + +pub fn log_events(events: &[Event]) { + for e in events { + trace!( + target: "executor", + "event emitted keys=[{}]", + e.keys.iter().map(|key| format!("{key:#x}")).collect::>().join(", ") + ); + } +} diff --git a/crates/katana/executor/tests/executor.rs b/crates/katana/executor/tests/executor.rs new file mode 100644 index 0000000000..70a85ee6fb --- /dev/null +++ b/crates/katana/executor/tests/executor.rs @@ -0,0 +1,329 @@ +mod fixtures; + +use std::collections::HashMap; + +use fixtures::{state_provider, valid_blocks}; +use katana_executor::{ExecutionOutput, ExecutorFactory}; +use katana_primitives::block::ExecutableBlock; +use katana_primitives::contract::ContractAddress; +use katana_primitives::genesis::constant::{ + DEFAULT_FEE_TOKEN_ADDRESS, DEFAULT_LEGACY_ERC20_CONTRACT_CLASS_HASH, + DEFAULT_OZ_ACCOUNT_CONTRACT_CLASS_HASH, DEFAULT_PREFUNDED_ACCOUNT_BALANCE, DEFAULT_UDC_ADDRESS, +}; +use katana_primitives::transaction::TxWithHash; +use katana_primitives::FieldElement; +use katana_provider::traits::state::StateProvider; +use starknet::core::utils::{ + get_storage_var_address, get_udc_deployed_address, UdcUniqueSettings, UdcUniqueness, +}; +use starknet::macros::felt; + +fn test_executor_with_valid_blocks_impl( + factory: EF, + state: Box, + blocks: [ExecutableBlock; 3], +) { + let cfg_env = factory.cfg(); + + // the contract address of the main account used to send most of the transactions + let main_account: ContractAddress = + felt!("0x6b86e40118f29ebe393a75469b4d926c7a44c2e2681b6d319520b7c1156d114").into(); + // the contract address of the account deployed using the `DeployAccount` tx + let new_acc: ContractAddress = + felt!("0x3ddfa445a70b927497249f94ff7431fc2e2abc761a34417fd4891beb7c2db85").into(); + + let mut executor = factory.with_state(state); + let mut expected_txs: Vec = Vec::with_capacity(3); + + // block 1 + // + + let block = &blocks[0]; + expected_txs.extend(block.body.iter().map(|t| t.into())); + + executor.execute_block(block.clone()).unwrap(); + + // assert that the block env is correctly set + let actual_block_env = executor.block_env(); + assert_eq!(actual_block_env.number, block.header.number); + assert_eq!(actual_block_env.timestamp, block.header.timestamp); + assert_eq!(actual_block_env.l1_gas_prices, block.header.gas_prices); + assert_eq!(actual_block_env.sequencer_address, block.header.sequencer_address); + + let transactions = executor.transactions(); + assert_eq!(transactions.len(), 2, "2 transactions were executed"); + + // asserts that the states are updated correctly after executing the 1st block + + let state_provider = executor.state(); + + // assert that the nonce of the main contract is updated, 3 txs were executed + let nonce = state_provider.nonce(main_account).unwrap().expect("nonce should exist"); + assert_eq!(nonce, 2u64.into(), "account nonce is updated"); + + let updated_main_acc_balance = state_provider + .storage( + cfg_env.fee_token_addresses.eth, + // the storage slot of the lower half of the fee balance + get_storage_var_address("ERC20_balances", &[main_account.into()]).unwrap(), // felt!("0x6e78596cd9cb5c7ef89ba020ffb848c0926c43c652ac5f9e219d0c8267caefe"), + ) + .unwrap() + .expect("storage should exist"); + + let actual_new_acc_balance = state_provider + .storage( + cfg_env.fee_token_addresses.eth, + // the storage slot of the lower half of the fee balance + get_storage_var_address("ERC20_balances", &[new_acc.into()]).unwrap(), + ) + .unwrap() + .expect("storage should exist"); + + assert!( + updated_main_acc_balance < FieldElement::from(DEFAULT_PREFUNDED_ACCOUNT_BALANCE), + "sender balance should decrease" + ); + assert_eq!(actual_new_acc_balance, felt!("0x9999999999999999"), "account balance is updated"); + + // assert that the sierra class is declared + let expected_class_hash = felt!("0x420"); + + let (casm, sierra) = fixtures::contract_class(); + let actual_casm = state_provider.class(expected_class_hash).unwrap(); + let actual_sierra = state_provider.sierra_class(expected_class_hash).unwrap(); + + assert_eq!(actual_casm, Some(casm), "casm class should be declared"); + assert_eq!(actual_sierra, Some(sierra), "sierra class should be declared"); + + let expected_compiled_class_hash = + felt!("0x016c6081eb34ad1e0c5513234ed0c025b3c7f305902d291bad534cd6474c85bc"); + let actual_compiled_hash = + state_provider.compiled_class_hash_of_class_hash(expected_class_hash).unwrap(); + assert_eq!( + actual_compiled_hash, + Some(expected_compiled_class_hash), + "compiled hash should be declared" + ); + + // block 2 + // + + let block = &blocks[1]; + expected_txs.extend(block.body.iter().map(|t| t.into())); + + executor.execute_block(block.clone()).unwrap(); + + // assert that the block env is correctly set + let actual_block_env = executor.block_env(); + assert_eq!(actual_block_env.number, block.header.number); + assert_eq!(actual_block_env.timestamp, block.header.timestamp); + assert_eq!(actual_block_env.l1_gas_prices, block.header.gas_prices); + assert_eq!(actual_block_env.sequencer_address, block.header.sequencer_address); + + let transactions = executor.transactions(); + assert_eq!(transactions.len(), 3, "3 transactions were executed"); + + // asserts that the states are updated correctly after executing the 2nd block + + let state_provider = executor.state(); + + // assert that the deploy account tx executed correctly + let actual_new_acc_class_hash = state_provider.class_hash_of_contract(new_acc).unwrap(); + let actual_new_acc_nonce = state_provider.nonce(new_acc).unwrap(); + + assert_eq!( + actual_new_acc_class_hash, + Some(DEFAULT_OZ_ACCOUNT_CONTRACT_CLASS_HASH), + "account should be deployed" + ); + assert_eq!(actual_new_acc_nonce, Some(1u64.into()), "account nonce is updated"); + + let updated_new_acc_balance = state_provider + .storage( + cfg_env.fee_token_addresses.eth, + // the storage slot of the lower half of the fee balance + felt!("0x7c8bacc8c8a7db5e5d4e22ab58750239183ae3e08b17a07a486f85fe8aee391"), + ) + .unwrap() + .expect("storage should exist"); + + assert!( + updated_new_acc_balance < felt!("0x9999999999999999"), + "account balance should be updated" + ); + + // block 3 + // + + let block = &blocks[2]; + expected_txs.extend(block.body.iter().map(|t| t.into())); + + executor.execute_block(block.clone()).unwrap(); + + // assert that the block env is correctly set + let actual_block_env = executor.block_env(); + assert_eq!(actual_block_env.number, block.header.number); + assert_eq!(actual_block_env.timestamp, block.header.timestamp); + assert_eq!(actual_block_env.l1_gas_prices, block.header.gas_prices); + assert_eq!(actual_block_env.sequencer_address, block.header.sequencer_address); + + let transactions = executor.transactions(); + assert_eq!( + transactions.len(), + 4, + "should not change bcs no transactions were executed in block 3" + ); + + // compute the contract address that we deploy thru the UDC using Invoke tx + let deployed_contract = get_udc_deployed_address( + felt!("0x6ea2ff5aa6f633708e69f5c61d2ac5f860d2435b46ddbd016aa065bce25100a"), + felt!("0x02a8846878b6ad1f54f6ba46f5f40e11cee755c677f130b2c4b60566c9003f1f"), + &UdcUniqueness::Unique(UdcUniqueSettings { + deployer_address: *main_account, + udc_contract_address: DEFAULT_UDC_ADDRESS.into(), + }), + &[ + felt!("0x4b415249"), + felt!("0x4b415249"), + felt!("0x12"), + felt!("0x1b39"), + felt!("0x0"), + felt!("0x6b86e40118f29ebe393a75469b4d926c7a44c2e2681b6d319520b7c1156d114"), + ], + ); + + let state_provider = executor.state(); + + let actual_deployed_contract_class_hash = + state_provider.class_hash_of_contract(deployed_contract.into()).unwrap(); + let actual_storage_value_1 = state_provider + .storage(deployed_contract.into(), get_storage_var_address("ERC20_name", &[]).unwrap()) + .unwrap(); + let actual_storage_value_2 = state_provider + .storage(deployed_contract.into(), get_storage_var_address("ERC20_symbol", &[]).unwrap()) + .unwrap(); + let actual_storage_value_3 = state_provider + .storage(deployed_contract.into(), get_storage_var_address("ERC20_decimals", &[]).unwrap()) + .unwrap(); + let actual_storage_value_4 = state_provider + .storage( + deployed_contract.into(), + get_storage_var_address("ERC20_total_supply", &[]).unwrap(), + ) + .unwrap(); + let actual_storage_value_4_1 = state_provider + .storage( + deployed_contract.into(), + get_storage_var_address("ERC20_total_supply", &[]).unwrap() + 1u8.into(), + ) + .unwrap(); + let actual_storage_value_5 = state_provider + .storage( + deployed_contract.into(), + get_storage_var_address("ERC20_balances", &[main_account.into()]).unwrap(), + ) + .unwrap(); + + assert_eq!( + actual_deployed_contract_class_hash, + Some(DEFAULT_LEGACY_ERC20_CONTRACT_CLASS_HASH), + "contract should be deployed" + ); + assert_eq!(actual_storage_value_1, Some(felt!("0x4b415249")), "ERC_name should be set"); + assert_eq!(actual_storage_value_2, Some(felt!("0x4b415249")), "ERC_symbol should be set"); + assert_eq!(actual_storage_value_3, Some(felt!("0x12")), "ERC_decimals should be set"); + assert_eq!( + actual_storage_value_4, + Some(felt!("0x1b39")), + "ERC_total_supply lower should be set" + ); + assert_eq!( + actual_storage_value_4_1, + Some(felt!("0x0")), + "ERC_total_supply higher should be set" + ); + assert_eq!( + actual_storage_value_5, + Some(felt!("0x1b39")), + "ERC_balances recepient should be set" + ); + + // assert the state updates after all the blocks are executed + // + + // assert the state updates + let ExecutionOutput { states, transactions } = executor.take_execution_output().unwrap(); + // asserts that the executed transactions are stored + let actual_txs: Vec = transactions.iter().map(|(tx, _)| tx.clone()).collect(); + + assert_eq!(actual_txs, expected_txs); + + let actual_nonce_updates = states.state_updates.nonce_updates; + let expected_nonce_updates = HashMap::from([(main_account, felt!("3")), (new_acc, felt!("1"))]); + + let actual_declared_classes = states.state_updates.declared_classes; + let expected_declared_classes = HashMap::from([( + felt!("0x420"), + felt!("0x016c6081eb34ad1e0c5513234ed0c025b3c7f305902d291bad534cd6474c85bc"), + )]); + + let actual_contract_deployed = states.state_updates.contract_updates; + let expected_contract_deployed = HashMap::from([ + (new_acc, DEFAULT_OZ_ACCOUNT_CONTRACT_CLASS_HASH), + (deployed_contract.into(), DEFAULT_LEGACY_ERC20_CONTRACT_CLASS_HASH), + ]); + + similar_asserts::assert_eq!(actual_nonce_updates, expected_nonce_updates); + similar_asserts::assert_eq!(actual_declared_classes, expected_declared_classes); + similar_asserts::assert_eq!(actual_contract_deployed, expected_contract_deployed); + + // TODO: asserts the storage updates + let actual_storage_updates = states.state_updates.storage_updates; + assert_eq!(actual_storage_updates.len(), 3, "only 3 contracts whose storage should be updated"); + assert!( + actual_storage_updates.get(&DEFAULT_FEE_TOKEN_ADDRESS).is_some(), + "fee token storage must get updated" + ); + assert!( + actual_storage_updates.get(&(deployed_contract.into())).is_some(), + "deployed contract storage must get updated" + ); + assert!( + actual_storage_updates.get(&new_acc).is_some(), + "newly deployed account storage must get updated" + ); +} + +#[cfg(feature = "blockifier")] +mod blockifier { + use fixtures::blockifier::factory; + use katana_executor::implementation::blockifier::BlockifierFactory; + + use super::*; + + #[rstest::rstest] + fn test_executor_with_valid_blocks( + factory: BlockifierFactory, + #[from(state_provider)] state: Box, + #[from(valid_blocks)] blocks: [ExecutableBlock; 3], + ) { + test_executor_with_valid_blocks_impl(factory, state, blocks) + } +} + +#[cfg(feature = "sir")] +mod sir { + use fixtures::sir::factory; + use katana_executor::implementation::sir::NativeExecutorFactory; + + use super::*; + + #[rstest::rstest] + fn test_executor_with_valid_blocks( + factory: NativeExecutorFactory, + #[from(state_provider)] state: Box, + #[from(valid_blocks)] blocks: [ExecutableBlock; 3], + ) { + test_executor_with_valid_blocks_impl(factory, state, blocks) + } +} diff --git a/crates/katana/executor/tests/fixtures/contract.json b/crates/katana/executor/tests/fixtures/contract.json new file mode 120000 index 0000000000..ce1957cd94 --- /dev/null +++ b/crates/katana/executor/tests/fixtures/contract.json @@ -0,0 +1 @@ +../../../primitives/contracts/compiled/oz_account_080.json \ No newline at end of file diff --git a/crates/katana/primitives/contracts/compiled/test_contract.json b/crates/katana/executor/tests/fixtures/legacy_contract.json similarity index 100% rename from crates/katana/primitives/contracts/compiled/test_contract.json rename to crates/katana/executor/tests/fixtures/legacy_contract.json diff --git a/crates/katana/executor/tests/fixtures/mod.rs b/crates/katana/executor/tests/fixtures/mod.rs new file mode 100644 index 0000000000..9a7f04ca8d --- /dev/null +++ b/crates/katana/executor/tests/fixtures/mod.rs @@ -0,0 +1,294 @@ +pub mod transaction; + +use std::collections::HashMap; + +use cairo_vm::vm::runners::builtin_runner::{ + BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, + OUTPUT_BUILTIN_NAME, POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, + SEGMENT_ARENA_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, +}; +use katana_executor::implementation::noop::NoopExecutorFactory; +use katana_executor::{ExecutorFactory, SimulationFlag}; +use katana_primitives::block::{ + Block, ExecutableBlock, FinalityStatus, GasPrices, PartialHeader, SealedBlockWithStatus, +}; +use katana_primitives::chain::ChainId; +use katana_primitives::class::{CompiledClass, FlattenedSierraClass}; +use katana_primitives::contract::ContractAddress; +use katana_primitives::env::{CfgEnv, FeeTokenAddressses}; +use katana_primitives::genesis::allocation::DevAllocationsGenerator; +use katana_primitives::genesis::constant::{ + DEFAULT_FEE_TOKEN_ADDRESS, DEFAULT_PREFUNDED_ACCOUNT_BALANCE, +}; +use katana_primitives::genesis::Genesis; +use katana_primitives::transaction::{ + DeclareTx, DeclareTxV2, DeclareTxWithClass, DeployAccountTx, DeployAccountTxV1, ExecutableTx, + ExecutableTxWithHash, InvokeTx, InvokeTxV1, +}; +use katana_primitives::utils::class::{parse_compiled_class, parse_sierra_class}; +use katana_primitives::version::Version; +use katana_primitives::FieldElement; +use katana_provider::providers::in_memory::InMemoryProvider; +use katana_provider::traits::block::BlockWriter; +use katana_provider::traits::state::{StateFactoryProvider, StateProvider}; +use starknet::macros::felt; + +// TODO: remove support for legacy contract declaration +#[allow(unused)] +pub fn legacy_contract_class() -> CompiledClass { + let json = include_str!("legacy_contract.json"); + let artifact = serde_json::from_str(json).unwrap(); + parse_compiled_class(artifact).unwrap() +} + +pub fn contract_class() -> (CompiledClass, FlattenedSierraClass) { + let json = include_str!("contract.json"); + let artifact = serde_json::from_str(json).unwrap(); + + let sierra = parse_sierra_class(json).unwrap().flatten().unwrap(); + let compiled = parse_compiled_class(artifact).unwrap(); + + (compiled, sierra) +} + +#[rstest::fixture] +#[once] +pub fn genesis() -> Genesis { + let mut seed = [0u8; 32]; + seed[0] = b'0'; + + let accounts = DevAllocationsGenerator::new(10) + .with_seed(seed) + .with_balance(DEFAULT_PREFUNDED_ACCOUNT_BALANCE) + .generate(); + + let mut genesis = Genesis::default(); + genesis.extend_allocations(accounts.into_iter().map(|(k, v)| (k, v.into()))); + genesis +} + +/// Returns a state provider with some prefilled states. +#[rstest::fixture] +pub fn state_provider(genesis: &Genesis) -> Box { + let states = genesis.state_updates(); + let provider = InMemoryProvider::new(); + + let block = SealedBlockWithStatus { + status: FinalityStatus::AcceptedOnL2, + block: Block::default().seal_with_hash(123u64.into()), + }; + + provider + .insert_block_with_states_and_receipts(block, states, vec![], vec![]) + .expect("able to insert block"); + + ::latest(&provider).unwrap() +} + +// TODO: update the txs to include valid signatures +/// Returns an array of blocks with transaction that are valid against the state by +/// [state_provider]. +#[rstest::fixture] +pub fn valid_blocks() -> [ExecutableBlock; 3] { + let version = Version::new(0, 13, 0); + let chain_id = ChainId::parse("KATANA").unwrap(); + let sequencer_address = ContractAddress(1u64.into()); + + let sender_address = ContractAddress(felt!( + "0x06b86e40118f29ebe393a75469b4d926c7a44c2e2681b6d319520b7c1156d114" + )); + + let gas_prices = GasPrices { eth: 100 * u128::pow(10, 9), strk: 100 * u128::pow(10, 9) }; + + [ + ExecutableBlock { + header: PartialHeader { + version, + number: 1, + timestamp: 100, + sequencer_address, + parent_hash: 123u64.into(), + gas_prices: gas_prices.clone(), + }, + body: vec![ + // fund the account to be deployed, sending 0x9999999999999 amount + ExecutableTxWithHash::new(ExecutableTx::Invoke(InvokeTx::V1(InvokeTxV1 { + chain_id, + sender_address, + calldata: vec![ + felt!("0x1"), + felt!("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"), + felt!("0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e"), + felt!("0x3"), + felt!("0x3ddfa445a70b927497249f94ff7431fc2e2abc761a34417fd4891beb7c2db85"), + felt!("0x9999999999999999"), + felt!("0x0"), + ], + max_fee: 4367000000000000, + signature: vec![], + nonce: FieldElement::ZERO, + }))), + // declare contract + ExecutableTxWithHash::new(ExecutableTx::Declare({ + let (compiled_class, sierra) = contract_class(); + DeclareTxWithClass { + compiled_class, + sierra_class: Some(sierra), + transaction: DeclareTx::V2(DeclareTxV2 { + nonce: FieldElement::ONE, + max_fee: 982300000000000, + chain_id, + signature: vec![], + sender_address, + class_hash: felt!("0x420"), + compiled_class_hash: felt!( + "0x16c6081eb34ad1e0c5513234ed0c025b3c7f305902d291bad534cd6474c85bc" + ), + }), + } + })), + ], + }, + ExecutableBlock { + header: PartialHeader { + version, + number: 2, + timestamp: 200, + sequencer_address, + parent_hash: 1234u64.into(), + gas_prices: gas_prices.clone(), + }, + body: vec![ + // deploy account tx with the default account class + ExecutableTxWithHash::new(ExecutableTx::DeployAccount(DeployAccountTx::V1( + DeployAccountTxV1 { + chain_id, + max_fee: 1443900000000000, + signature: vec![], + nonce: 0u64.into(), + contract_address_salt: felt!( + "0x2ce091f544a799160324295e62da74d194eda204682b5b8fd0dd4d2f8f5ab18" + ), + constructor_calldata: vec![felt!( + "0x4c339f18b9d1b95b64a6d378abd1480b2e0d5d5bd33cd0828cbce4d65c27284" + )], + class_hash: felt!( + "0x5400e90f7e0ae78bd02c77cd75527280470e2fe19c54970dd79dc37a9d3645c" + ), + contract_address: ContractAddress(felt!( + "0x3ddfa445a70b927497249f94ff7431fc2e2abc761a34417fd4891beb7c2db85" + )), + }, + ))), + ], + }, + ExecutableBlock { + header: PartialHeader { + version, + number: 3, + timestamp: 300, + sequencer_address, + parent_hash: 12345u64.into(), + gas_prices: gas_prices.clone(), + }, + body: vec![ + // deploy contract using UDC + ExecutableTxWithHash::new(ExecutableTx::Invoke(InvokeTx::V1(InvokeTxV1 { + chain_id, + sender_address, + calldata: vec![ + felt!("0x1"), + felt!("0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf"), + felt!("0x1987cbd17808b9a23693d4de7e246a443cfe37e6e7fbaeabd7d7e6532b07c3d"), + felt!("0xa"), + felt!("0x2a8846878b6ad1f54f6ba46f5f40e11cee755c677f130b2c4b60566c9003f1f"), + felt!("0x6ea2ff5aa6f633708e69f5c61d2ac5f860d2435b46ddbd016aa065bce25100a"), + felt!("0x1"), + felt!("0x6"), + felt!("0x4b415249"), + felt!("0x4b415249"), + felt!("0x12"), + felt!("0x1b39"), + felt!("0x0"), + sender_address.into(), + ], + max_fee: 2700700000000000, + signature: vec![], + nonce: FieldElement::TWO, + }))), + ], + }, + ] +} + +#[rstest::fixture] +pub fn cfg() -> CfgEnv { + let fee_token_addresses = + FeeTokenAddressses { eth: DEFAULT_FEE_TOKEN_ADDRESS, strk: ContractAddress(222u64.into()) }; + + let vm_resource_fee_cost = HashMap::from([ + (String::from("n_steps"), 1_f64), + (HASH_BUILTIN_NAME.to_string(), 1_f64), + (RANGE_CHECK_BUILTIN_NAME.to_string(), 1_f64), + (SIGNATURE_BUILTIN_NAME.to_string(), 1_f64), + (BITWISE_BUILTIN_NAME.to_string(), 1_f64), + (POSEIDON_BUILTIN_NAME.to_string(), 1_f64), + (OUTPUT_BUILTIN_NAME.to_string(), 1_f64), + (EC_OP_BUILTIN_NAME.to_string(), 1_f64), + (KECCAK_BUILTIN_NAME.to_string(), 1_f64), + (SEGMENT_ARENA_BUILTIN_NAME.to_string(), 1_f64), + ]); + + CfgEnv { + fee_token_addresses, + vm_resource_fee_cost, + max_recursion_depth: 100, + validate_max_n_steps: 1_000_000, + invoke_tx_max_n_steps: 1_000_000, + chain_id: ChainId::parse("KATANA").unwrap(), + } +} + +// TODO: test both with and without the flags turned on +#[rstest::fixture] +pub fn flags( + #[default(false)] skip_validate: bool, + #[default(false)] skip_fee_transfer: bool, +) -> SimulationFlag { + SimulationFlag { skip_validate, skip_fee_transfer, ..Default::default() } +} + +/// A fixture that provides a default `ExecutorFactory` implementation. +#[rstest::fixture] +#[default(NoopExecutorFactory)] +pub fn executor_factory( + #[default(NoopExecutorFactory::new())] factory: EF, +) -> EF { + factory +} + +#[cfg(feature = "blockifier")] +pub mod blockifier { + use katana_executor::implementation::blockifier::BlockifierFactory; + use katana_executor::SimulationFlag; + + use super::{cfg, flags, CfgEnv}; + + #[rstest::fixture] + pub fn factory(cfg: CfgEnv, #[with(true)] flags: SimulationFlag) -> BlockifierFactory { + BlockifierFactory::new(cfg, flags) + } +} + +#[cfg(feature = "sir")] +pub mod sir { + use katana_executor::implementation::sir::NativeExecutorFactory; + use katana_executor::SimulationFlag; + + use super::{cfg, flags, CfgEnv}; + + #[rstest::fixture] + pub fn factory(cfg: CfgEnv, #[with(true)] flags: SimulationFlag) -> NativeExecutorFactory { + NativeExecutorFactory::new(cfg, flags) + } +} diff --git a/crates/katana/executor/tests/fixtures/transaction.rs b/crates/katana/executor/tests/fixtures/transaction.rs new file mode 100644 index 0000000000..b8819691b9 --- /dev/null +++ b/crates/katana/executor/tests/fixtures/transaction.rs @@ -0,0 +1,111 @@ +use katana_primitives::chain::ChainId; +use katana_primitives::contract::{ContractAddress, Nonce}; +use katana_primitives::env::CfgEnv; +use katana_primitives::genesis::allocation::GenesisAllocation; +use katana_primitives::genesis::constant::DEFAULT_FEE_TOKEN_ADDRESS; +use katana_primitives::genesis::Genesis; +use katana_primitives::transaction::ExecutableTxWithHash; +use katana_primitives::FieldElement; +use starknet::accounts::{Account, Call, ExecutionEncoding, SingleOwnerAccount}; +use starknet::core::types::BroadcastedInvokeTransaction; +use starknet::macros::{felt, selector}; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::{JsonRpcClient, Url}; +use starknet::signers::{LocalWallet, SigningKey}; + +use super::{cfg, genesis}; + +#[allow(unused)] +pub fn invoke_executable_tx( + address: ContractAddress, + private_key: FieldElement, + chain_id: ChainId, + nonce: Nonce, + max_fee: FieldElement, + signed: bool, +) -> ExecutableTxWithHash { + let url = "http://localhost:5050"; + let provider = JsonRpcClient::new(HttpTransport::new(Url::try_from(url).unwrap())); + let signer = LocalWallet::from_signing_key(SigningKey::from_secret_scalar(private_key)); + + let account = SingleOwnerAccount::new( + provider, + signer, + address.into(), + chain_id.into(), + ExecutionEncoding::New, + ); + + let calls = vec![Call { + to: DEFAULT_FEE_TOKEN_ADDRESS.into(), + selector: selector!("transfer"), + calldata: vec![felt!("0x1"), felt!("0x99"), felt!("0x0")], + }]; + + let tx = account.execute(calls).nonce(nonce).max_fee(max_fee).prepared().unwrap(); + + let mut broadcasted_tx = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(tx.get_invoke_request(false)) + .unwrap(); + + if !signed { + match broadcasted_tx { + BroadcastedInvokeTransaction::V1(ref mut tx) => tx.signature = vec![], + BroadcastedInvokeTransaction::V3(ref mut tx) => tx.signature = vec![], + } + } + + let tx = katana_rpc_types::transaction::BroadcastedInvokeTx(broadcasted_tx) + .into_tx_with_chain_id(chain_id); + + ExecutableTxWithHash::new(tx.into()) +} + +#[rstest::fixture] +fn signed() -> bool { + true +} + +#[rstest::fixture] +pub fn executable_tx(signed: bool, genesis: &Genesis, cfg: CfgEnv) -> ExecutableTxWithHash { + let (addr, alloc) = genesis.allocations.first_key_value().expect("should have account"); + + let GenesisAllocation::Account(account) = alloc else { + panic!("should be account"); + }; + + invoke_executable_tx( + *addr, + account.private_key().unwrap(), + cfg.chain_id, + FieldElement::ZERO, + // this is an arbitrary large fee so that it doesn't fail + felt!("0x999999999999999"), + signed, + ) +} + +#[rstest::fixture] +pub fn executable_tx_without_max_fee( + signed: bool, + genesis: &Genesis, + cfg: CfgEnv, +) -> ExecutableTxWithHash { + let (addr, alloc) = genesis.allocations.first_key_value().expect("should have account"); + + let GenesisAllocation::Account(account) = alloc else { + panic!("should be account"); + }; + + invoke_executable_tx( + *addr, + account.private_key().unwrap(), + cfg.chain_id, + FieldElement::ZERO, + FieldElement::ZERO, + signed, + ) +} diff --git a/crates/katana/executor/tests/simulate.rs b/crates/katana/executor/tests/simulate.rs new file mode 100644 index 0000000000..7a8905fa43 --- /dev/null +++ b/crates/katana/executor/tests/simulate.rs @@ -0,0 +1,115 @@ +mod fixtures; + +use fixtures::transaction::executable_tx; +use fixtures::{executor_factory, state_provider}; +use katana_executor::{ExecutionOutput, ExecutorFactory, SimulationFlag}; +use katana_primitives::block::GasPrices; +use katana_primitives::env::BlockEnv; +use katana_primitives::transaction::ExecutableTxWithHash; +use katana_provider::traits::state::StateProvider; +use rstest_reuse::{self, *}; +use starknet::core::types::PriceUnit; +use starknet::macros::felt; + +#[rstest::fixture] +fn block_env() -> BlockEnv { + let l1_gas_prices = GasPrices { eth: 1000, strk: 1000 }; + BlockEnv { l1_gas_prices, sequencer_address: felt!("0x1").into(), ..Default::default() } +} + +#[template] +#[rstest::rstest] +#[case::tx(executable_tx::default(), SimulationFlag::new())] +#[case::tx_skip_validate(executable_tx::default(), SimulationFlag::new().skip_validate())] +#[case::tx_no_signature_skip_validate(executable_tx::partial_1(false), SimulationFlag::new().skip_validate())] +#[should_panic] +#[case::tx_no_signature(executable_tx::partial_1(false), SimulationFlag::new())] +fn simulate_tx( + executor_factory: EF, + block_env: BlockEnv, + state_provider: Box, + #[case] tx: ExecutableTxWithHash, + #[case] flags: SimulationFlag, +) { +} + +#[allow(unused)] +fn test_simulate_tx_impl( + executor_factory: EF, + block_env: BlockEnv, + state_provider: Box, + tx: ExecutableTxWithHash, + flags: SimulationFlag, +) { + let transactions = vec![tx]; + let mut executor = executor_factory.with_state_and_block_env(state_provider, block_env); + + let results = executor.simulate(transactions.clone(), flags.clone()); + let fees = executor.estimate_fee(transactions, flags); + + assert!(results.iter().all(|res| res.result.is_success()), "all txs should be successful"); + assert!(fees.iter().all(|res| { + match res { + // makes sure that the fee is non-zero + Ok(fee) => { + fee.gas_price != 0 + && fee.gas_consumed != 0 + && fee.overall_fee != 0 + && fee.unit == PriceUnit::Wei // TODO: add a tx that use STRK + } + Err(_) => false, + } + }),); + + // check that the underlying state is not modified + let ExecutionOutput { states, transactions } = + executor.take_execution_output().expect("must take output"); + + assert!(transactions.is_empty(), "simulated tx should not be stored"); + + assert!(states.state_updates.nonce_updates.is_empty(), "no state updates"); + assert!(states.state_updates.storage_updates.is_empty(), "no state updates"); + assert!(states.state_updates.contract_updates.is_empty(), "no state updates"); + assert!(states.state_updates.declared_classes.is_empty(), "no state updates"); + + assert!(states.declared_sierra_classes.is_empty(), "no new classes should be declared"); + assert!(states.declared_compiled_classes.is_empty(), "no new classes should be declared"); +} + +#[cfg(feature = "blockifier")] +mod blockifier { + use fixtures::blockifier::factory; + use katana_executor::implementation::blockifier::BlockifierFactory; + + use super::*; + + #[apply(simulate_tx)] + fn test_simulate_tx( + #[with(factory::default())] executor_factory: BlockifierFactory, + block_env: BlockEnv, + state_provider: Box, + #[case] tx: ExecutableTxWithHash, + #[case] flags: SimulationFlag, + ) { + test_simulate_tx_impl(executor_factory, block_env, state_provider, tx, flags); + } +} + +#[cfg(feature = "sir")] +mod sir { + use fixtures::sir::factory; + use katana_executor::implementation::sir::NativeExecutorFactory; + + use super::*; + + #[apply(simulate_tx)] + fn test_simulate_tx( + #[with(factory::default())] executor_factory: NativeExecutorFactory, + block_env: BlockEnv, + state_provider: Box, + #[case] tx: ExecutableTxWithHash, + #[case] flags: SimulationFlag, + ) { + test_simulate_tx_impl(executor_factory, block_env, state_provider, tx, flags); + } +} diff --git a/crates/katana/primitives/Cargo.toml b/crates/katana/primitives/Cargo.toml index 534176db9f..a2ec69ca12 100644 --- a/crates/katana/primitives/Cargo.toml +++ b/crates/katana/primitives/Cargo.toml @@ -15,7 +15,7 @@ lazy_static = "1.4.0" rand = { version = "0.8.5", features = [ "small_rng" ] } rayon.workspace = true serde.workspace = true -serde_json.workspace = true +serde_json = { workspace = true, features = [ "arbitrary_precision" ] } serde_with.workspace = true starknet-crypto = "0.6.1" starknet.workspace = true @@ -23,7 +23,7 @@ strum.workspace = true strum_macros.workspace = true thiserror.workspace = true -blockifier.workspace = true +cairo-lang-sierra.workspace = true cairo-lang-starknet.workspace = true flate2.workspace = true starknet_api.workspace = true @@ -31,8 +31,6 @@ starknet_api.workspace = true ethers = "2.0.11" [features] -default = [ "blockifier", "serde" ] - -blockifier = [ ] +default = [ "serde" ] rpc = [ ] serde = [ ] diff --git a/crates/katana/primitives/contracts/compiled/account.json b/crates/katana/primitives/contracts/compiled/account.json index f015ab90e6..195603b14e 100644 --- a/crates/katana/primitives/contracts/compiled/account.json +++ b/crates/katana/primitives/contracts/compiled/account.json @@ -1,4579 +1,5698 @@ { - "abi": [ - { - "members": [ - { "name": "to", "offset": 0, "type": "felt" }, - { "name": "selector", "offset": 1, "type": "felt" }, - { "name": "data_offset", "offset": 2, "type": "felt" }, - { "name": "data_len", "offset": 3, "type": "felt" } - ], - "name": "AccountCallArray", - "size": 4, - "type": "struct" - }, - { - "inputs": [{ "name": "publicKey", "type": "felt" }], - "name": "constructor", - "outputs": [], - "type": "constructor" - }, - { - "inputs": [], - "name": "getPublicKey", - "outputs": [{ "name": "publicKey", "type": "felt" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "name": "interfaceId", "type": "felt" }], - "name": "supportsInterface", - "outputs": [{ "name": "success", "type": "felt" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [{ "name": "newPublicKey", "type": "felt" }], - "name": "setPublicKey", - "outputs": [], - "type": "function" - }, - { - "inputs": [ - { "name": "hash", "type": "felt" }, - { "name": "signature_len", "type": "felt" }, - { "name": "signature", "type": "felt*" } - ], - "name": "isValidSignature", - "outputs": [{ "name": "isValid", "type": "felt" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "name": "call_array_len", "type": "felt" }, - { "name": "call_array", "type": "AccountCallArray*" }, - { "name": "calldata_len", "type": "felt" }, - { "name": "calldata", "type": "felt*" } - ], - "name": "__validate__", - "outputs": [], - "type": "function" - }, - { - "inputs": [{ "name": "class_hash", "type": "felt" }], - "name": "__validate_declare__", - "outputs": [], - "type": "function" - }, - { - "inputs": [ - { "name": "class_hash", "type": "felt" }, - { "name": "salt", "type": "felt" }, - { "name": "publicKey", "type": "felt" } - ], - "name": "__validate_deploy__", - "outputs": [], - "type": "function" - }, - { - "inputs": [ - { "name": "call_array_len", "type": "felt" }, - { "name": "call_array", "type": "AccountCallArray*" }, - { "name": "calldata_len", "type": "felt" }, - { "name": "calldata", "type": "felt*" } - ], - "name": "__execute__", - "outputs": [ - { "name": "response_len", "type": "felt" }, - { "name": "response", "type": "felt*" } - ], - "type": "function" - } - ], - "entry_points_by_type": { - "CONSTRUCTOR": [ - { - "offset": "0x16e", - "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194" - } - ], - "EXTERNAL": [ - { - "offset": "0x1cd", - "selector": "0xbc0eb87884ab91e330445c3584a50d7ddf4b568f02fbeb456a6242cce3f5d9" - }, - { - "offset": "0x2bb", - "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" - }, - { - "offset": "0x224", - "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" - }, - { - "offset": "0x191", - "selector": "0x1a6c6a0bdec86cc645c91997d8eea83e87148659e3e61122f72361fd5e94079" - }, - { - "offset": "0x1f4", - "selector": "0x213dfe25e2ca309c4d615a09cfc95fdb2fc7dc73fbcad12c450fe93b1f2ff9e" - }, - { - "offset": "0x25f", - "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3" - }, - { - "offset": "0x1b2", - "selector": "0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd" - }, - { - "offset": "0x285", - "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895" - } - ], - "L1_HANDLER": [] - }, - "program": { - "debug_info": { - "file_contents": {}, - "instruction_locations": {} - }, - "attributes": [ - { - "accessible_scopes": [ - "openzeppelin.account.library", - "openzeppelin.account.library.Account", - "openzeppelin.account.library.Account.assert_only_self" - ], - "end_pc": 192, - "flow_tracking_data": { - "ap_tracking": { "group": 16, "offset": 12 }, - "reference_ids": {} - }, - "name": "error_message", - "start_pc": 191, - "value": "Account: caller is not this account" - }, - { - "accessible_scopes": [ - "openzeppelin.account.library", - "openzeppelin.account.library.Account", - "openzeppelin.account.library.Account.execute" - ], - "end_pc": 269, - "flow_tracking_data": { - "ap_tracking": { "group": 21, "offset": 9 }, - "reference_ids": {} - }, - "name": "error_message", - "start_pc": 259, - "value": "Account: deprecated tx version" - }, - { - "accessible_scopes": [ - "openzeppelin.account.library", - "openzeppelin.account.library.Account", - "openzeppelin.account.library.Account.execute" - ], - "end_pc": 274, - "flow_tracking_data": { - "ap_tracking": { "group": 21, "offset": 49 }, - "reference_ids": {} - }, - "name": "error_message", - "start_pc": 272, - "value": "Account: reentrant call" - } - ], - "builtins": ["pedersen", "range_check", "ecdsa", "bitwise"], - "compiler_version": "0.10.2", - "data": [ - "0x40780017fff7fff", - "0x1", - "0x208b7fff7fff7ffe", - "0x20780017fff7ffd", - "0x3", - "0x208b7fff7fff7ffe", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480080007fff8000", - "0x400080007ffd7fff", - "0x482480017ffd8001", - "0x1", - "0x482480017ffd8001", - "0x1", - "0xa0680017fff7ffe", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffb", - "0x402a7ffc7ffd7fff", - "0x208b7fff7fff7ffe", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x484480017fff8000", - "0x2aaaaaaaaaaaab05555555555555556", - "0x48307fff7ffd8000", - "0x480280027ffb8000", - "0x480280037ffb8000", - "0x484480017fff8000", - "0x4000000000000088000000000000001", - "0x48307fff7ffd8000", - "0xa0680017fff8000", - "0xe", - "0x480680017fff8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x48287ffc80007fff", - "0x40307ffc7ff87fff", - "0x48297ffd80007ffc", - "0x482680017ffd8000", - "0x1", - "0x48507fff7ffe8000", - "0x40507ff97ff57fff", - "0x482680017ffb8000", - "0x4", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0xc", - "0x480680017fff8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x48287ffd80007fff", - "0x48327fff7ffc8000", - "0x40307ffa7ff67fff", - "0x48527ffe7ffc8000", - "0x40507ff97ff57fff", - "0x482680017ffb8000", - "0x4", - "0x208b7fff7fff7ffe", - "0x40317ffd7ff97ffd", - "0x48297ffc80007ffd", - "0x48527fff7ffc8000", - "0x40507ffb7ff77fff", - "0x40780017fff7fff", - "0x2", - "0x482680017ffb8000", - "0x4", - "0x208b7fff7fff7ffe", - "0x48297ffd80007ffc", - "0x20680017fff7fff", - "0x4", - "0x402780017ffc7ffc", - "0x1", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffcc", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x43616c6c436f6e7472616374", - "0x400280007ff97fff", - "0x400380017ff97ffa", - "0x400380027ff97ffb", - "0x400380037ff97ffc", - "0x400380047ff97ffd", - "0x482680017ff98000", - "0x7", - "0x480280057ff98000", - "0x480280067ff98000", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x47657443616c6c657241646472657373", - "0x400280007ffd7fff", - "0x482680017ffd8000", - "0x2", - "0x480280017ffd8000", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x476574436f6e747261637441646472657373", - "0x400280007ffd7fff", - "0x482680017ffd8000", - "0x2", - "0x480280017ffd8000", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x53746f7261676552656164", - "0x400280007ffc7fff", - "0x400380017ffc7ffd", - "0x482680017ffc8000", - "0x3", - "0x480280027ffc8000", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x53746f726167655772697465", - "0x400280007ffb7fff", - "0x400380017ffb7ffc", - "0x400380027ffb7ffd", - "0x482680017ffb8000", - "0x3", - "0x208b7fff7fff7ffe", - "0x480680017fff8000", - "0x4765745478496e666f", - "0x400280007ffd7fff", - "0x482680017ffd8000", - "0x2", - "0x480280017ffd8000", - "0x208b7fff7fff7ffe", - "0x400380017ff97ffa", - "0x400380007ff97ffb", - "0x482680017ff98000", - "0x2", - "0x208b7fff7fff7ffe", - "0xa0680017fff8000", - "0xc", - "0x40780017fff7fff", - "0x6", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff8c", - "0x480680017fff8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480a7ffb7fff8000", - "0x480a7ffd7fff8000", - "0x480a7ffc7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffb1", - "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x480680017fff8000", - "0x1379ac0624b939ceb9dede92211d7db5ee174fe28be72245b0a1a2abd81c98f", - "0x208b7fff7fff7ffe", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffa", - "0x480a7ffb7fff8000", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc6", - "0x48127ffe7fff8000", - "0x48127ff57fff8000", - "0x48127ff57fff8000", - "0x48127ffc7fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffed", - "0x480a7ffa7fff8000", - "0x48127ffe7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc0", - "0x48127ff67fff8000", - "0x48127ff67fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff1", - "0x208b7fff7fff7ffe", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffa4", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff9a", - "0x40127fff7fff7ff9", - "0x48127ffe7fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd5", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffe00365a", - "0x20680017fff7fff", - "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480680017fff8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffff59942a8c", - "0x20680017fff7fff", - "0x8", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480680017fff8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd7", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffbf", - "0x208b7fff7fff7ffe", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a7ffa7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffac", - "0x480a7ff97fff8000", - "0x480a7ffb7fff8000", - "0x48127ffd7fff8000", - "0x480280007ffd8000", - "0x480280017ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff87", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x48127ffd7fff8000", - "0x48127ff37fff8000", - "0x480680017fff8000", - "0x1", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x3", - "0x480a7ff57fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff74", - "0x480a7ff97fff8000", - "0x480680017fff8000", - "0x1", - "0x480080007ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff7a", - "0x480680017fff8000", - "0x1", - "0x40127fff7fff7ffe", - "0x40137ffd7fff8000", - "0x48127fdc7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff49", - "0x400680017fff7fff", - "0x0", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffeef", - "0x40137fff7fff8001", - "0x48127ffb7fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffd7fff8000", - "0x480a80017fff8000", - "0x1104800180018000", - "0x35", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffee5", - "0x40137fff7fff8002", - "0x48127ffc7fff8000", - "0x480a7ffa7fff8000", - "0x480a80017fff8000", - "0x480a80027fff8000", - "0x1104800180018000", - "0xa", - "0x48127ffe7fff8000", - "0x480a7ff67fff8000", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a80007fff8000", - "0x48127ffa7fff8000", - "0x480a80027fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x3", - "0x20780017fff7ffb", - "0x6", - "0x480a7ffa7fff8000", - "0x480680017fff8000", - "0x0", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480280007ffc8000", - "0x480280017ffc8000", - "0x480280027ffc8000", - "0x480280037ffc8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff11", - "0x40137ffe7fff8000", - "0x40137fff7fff8001", - "0x40137ffd7fff8002", - "0x480a7ffd7fff8000", - "0x480a80017fff8000", - "0x480a80007fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffec2", - "0x480a80027fff8000", - "0x482680017ffb8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x482680017ffc8000", - "0x4", - "0x482a80007ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe4", - "0x48127ffe7fff8000", - "0x482880007ffe8000", - "0x208b7fff7fff7ffe", - "0x20780017fff7ffa", - "0x4", - "0x480a7ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480280007ffb8000", - "0x400280007ffd7fff", - "0x480280017ffb8000", - "0x400280017ffd7fff", - "0x480280037ffb8000", - "0x400280027ffd7fff", - "0x480280027ffb8000", - "0x48327fff7ffc8000", - "0x400280037ffd7fff", - "0x480a7ff97fff8000", - "0x482680017ffa8000", - "0x800000000000011000000000000000000000000000000000000000000000000", - "0x482680017ffb8000", - "0x4", - "0x480a7ffc7fff8000", - "0x482680017ffd8000", - "0x4", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffec", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff48", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x1", - "0x402a7ffd7ffc7fff", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff3", - "0x40780017fff7fff", - "0x1", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480280037ffb8000", - "0x480280047ffb8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff3e", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x4003800080007ffc", - "0x4826800180008000", - "0x1", - "0x480a7ffd7fff8000", - "0x4828800080007ffe", - "0x480a80007fff8000", - "0x208b7fff7fff7ffe", - "0x402b7ffd7ffc7ffd", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280027ffb8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffee", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff1", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x48127ffb7fff8000", - "0x480280037ffb8000", - "0x480280047ffb8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff23", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x4003800080007ffc", - "0x4826800180008000", - "0x1", - "0x480a7ffd7fff8000", - "0x4828800080007ffe", - "0x480a80007fff8000", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x1", - "0x402a7ffd7ffc7fff", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffea", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffee", - "0x48127ff47fff8000", - "0x48127ff47fff8000", - "0x48127ffb7fff8000", - "0x480280037ffb8000", - "0x480280047ffb8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff19", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x1", - "0x402a7ffd7ffc7fff", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff3", - "0x40780017fff7fff", - "0x1", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x48127ffc7fff8000", - "0x480280037ffb8000", - "0x480280047ffb8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff04", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x1", - "0x4003800080007ffc", - "0x4826800180008000", - "0x1", - "0x480a7ffd7fff8000", - "0x4828800080007ffe", - "0x480a80007fff8000", - "0x208b7fff7fff7ffe", - "0x480280027ffb8000", - "0x480280017ffd8000", - "0x400080007ffe7fff", - "0x482680017ffd8000", - "0x2", - "0x480280017ffd8000", - "0x48307fff7ffe8000", - "0x402a7ffd7ffc7fff", - "0x480280027ffb8000", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280037ffb8000", - "0x482480017ffc8000", - "0x1", - "0x480280007ffd8000", - "0x480280017ffd8000", - "0x482680017ffd8000", - "0x2", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffdc", - "0x48127ffe7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe3", - "0x48127ff37fff8000", - "0x48127ff37fff8000", - "0x48127ffb7fff8000", - "0x48127ff27fff8000", - "0x480280047ffb8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff67fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe61", - "0x48127ffe7fff8000", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480080057ffb8000", - "0x480080037ffa8000", - "0x480080047ff98000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffecf", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x208b7fff7fff7ffe", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x400080007ffe7fff", - "0x482680017ffd8000", - "0x1", - "0x480280007ffd8000", - "0x484480017fff8000", - "0x4", - "0x48307fff7ffd8000", - "0x480280027ffb8000", - "0x480080007ffe8000", - "0x400080017ffe7fff", - "0x482480017ffd8000", - "0x1", - "0x480080007ffc8000", - "0x48307fff7ffe8000", - "0x402a7ffd7ffc7fff", - "0x480280027ffb8000", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280037ffb8000", - "0x482480017ffc8000", - "0x2", - "0x480280007ffd8000", - "0x482680017ffd8000", - "0x1", - "0x480080007ff38000", - "0x482480017ff28000", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd3", - "0x40780017fff7fff", - "0x1", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x480280047ffb8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff97fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe26", - "0x48127ffe7fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480080057ffb8000", - "0x480080037ffa8000", - "0x480080047ff98000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe94", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x1", - "0x402a7ffd7ffc7fff", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280037ffb8000", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe8", - "0x40780017fff7fff", - "0x1", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x480280047ffb8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff77fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe00", - "0x48127ffe7fff8000", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480080057ffb8000", - "0x480080037ffa8000", - "0x480080047ff98000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe6e", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x208b7fff7fff7ffe", - "0x482680017ffd8000", - "0x3", - "0x402a7ffd7ffc7fff", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280037ffb8000", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x480280017ffd8000", - "0x480280027ffd8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", - "0x40780017fff7fff", - "0x1", - "0x48127ffb7fff8000", - "0x48127ffb7fff8000", - "0x48127ffc7fff8000", - "0x48127ffa7fff8000", - "0x480280047ffb8000", - "0x480680017fff8000", - "0x0", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe", - "0x480a7ff57fff8000", - "0x480a7ff67fff8000", - "0x480a7ff77fff8000", - "0x480a7ff87fff8000", - "0x480a7ff97fff8000", - "0x480a7ffa7fff8000", - "0x480a7ffb7fff8000", - "0x480a7ffc7fff8000", - "0x480a7ffd7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe5a", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x3", - "0x4003800080007ffb", - "0x400380007ffd7ffb", - "0x402780017ffd8001", - "0x1", - "0x4826800180008000", - "0x1", - "0x40297ffb7fff8002", - "0x4826800180008000", - "0x1", - "0x480a7ffc7fff8000", - "0x480a7ffb7fff8000", - "0x1104800180018000", - "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffd4f", - "0x480a80017fff8000", - "0x4829800080008002", - "0x480a80007fff8000", - "0x208b7fff7fff7ffe", - "0x40780017fff7fff", - "0x4", - "0x480280027ffb8000", - "0x480280007ffd8000", - "0x400080007ffe7fff", - "0x482680017ffd8000", - "0x1", - "0x480280007ffd8000", - "0x484480017fff8000", - "0x4", - "0x48307fff7ffd8000", - "0x480280027ffb8000", - "0x480080007ffe8000", - "0x400080017ffe7fff", - "0x482480017ffd8000", - "0x1", - "0x480080007ffc8000", - "0x48307fff7ffe8000", - "0x402a7ffd7ffc7fff", - "0x480280027ffb8000", - "0x480280007ffb8000", - "0x480280017ffb8000", - "0x480280037ffb8000", - "0x480280047ffb8000", - "0x482480017ffb8000", - "0x2", - "0x480280007ffd8000", - "0x482680017ffd8000", - "0x1", - "0x480080007ff28000", - "0x482480017ff18000", - "0x1", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc2", - "0x40137ff97fff8000", - "0x40137ffa7fff8001", - "0x40137ffb7fff8002", - "0x40137ffc7fff8003", - "0x48127ffd7fff8000", - "0x1104800180018000", - "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc7", - "0x480a80007fff8000", - "0x480a80017fff8000", - "0x48127ffb7fff8000", - "0x480a80027fff8000", - "0x480a80037fff8000", - "0x48127ff97fff8000", - "0x48127ff97fff8000", - "0x208b7fff7fff7ffe" - ], - "hints": { - "0": [ - { - "accessible_scopes": [ - "starkware.cairo.common.alloc", - "starkware.cairo.common.alloc.alloc" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 0, "offset": 0 }, - "reference_ids": {} - } - } - ], - "6": [ - { - "accessible_scopes": [ - "starkware.cairo.common.memcpy", - "starkware.cairo.common.memcpy.memcpy" - ], - "code": "vm_enter_scope({'n': ids.len})", - "flow_tracking_data": { - "ap_tracking": { "group": 1, "offset": 0 }, - "reference_ids": { "starkware.cairo.common.memcpy.memcpy.len": 0 } - } - } - ], - "14": [ - { - "accessible_scopes": [ - "starkware.cairo.common.memcpy", - "starkware.cairo.common.memcpy.memcpy" - ], - "code": "n -= 1\nids.continue_copying = 1 if n > 0 else 0", - "flow_tracking_data": { - "ap_tracking": { "group": 1, "offset": 5 }, - "reference_ids": { - "starkware.cairo.common.memcpy.memcpy.continue_copying": 1 - } - } - } - ], - "17": [ - { - "accessible_scopes": [ - "starkware.cairo.common.memcpy", - "starkware.cairo.common.memcpy.memcpy" - ], - "code": "vm_exit_scope()", - "flow_tracking_data": { - "ap_tracking": { "group": 1, "offset": 6 }, - "reference_ids": {} - } - } - ], - "18": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math", - "starkware.cairo.common.math.assert_le_felt" - ], - "code": "import itertools\n\nfrom starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\na = ids.a % PRIME\nb = ids.b % PRIME\nassert a <= b, f'a = {a} is not less than or equal to b = {b}.'\n\n# Find an arc less than PRIME / 3, and another less than PRIME / 2.\nlengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]\nlengths_and_indices.sort()\nassert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2\nexcluded = lengths_and_indices[2][1]\n\nmemory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (\n divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))\nmemory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (\n divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))", - "flow_tracking_data": { - "ap_tracking": { "group": 2, "offset": 0 }, - "reference_ids": { - "starkware.cairo.common.math.assert_le_felt.a": 2, - "starkware.cairo.common.math.assert_le_felt.b": 3, - "starkware.cairo.common.math.assert_le_felt.range_check_ptr": 4 - } - } - } - ], - "28": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math", - "starkware.cairo.common.math.assert_le_felt" - ], - "code": "memory[ap] = 1 if excluded != 0 else 0", - "flow_tracking_data": { - "ap_tracking": { "group": 2, "offset": 8 }, - "reference_ids": {} - } - } - ], - "42": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math", - "starkware.cairo.common.math.assert_le_felt" - ], - "code": "memory[ap] = 1 if excluded != 1 else 0", - "flow_tracking_data": { - "ap_tracking": { "group": 2, "offset": 9 }, - "reference_ids": {} - } - } - ], - "54": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math", - "starkware.cairo.common.math.assert_le_felt" - ], - "code": "assert excluded == 2", - "flow_tracking_data": { - "ap_tracking": { "group": 2, "offset": 10 }, - "reference_ids": {} - } - } - ], - "63": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math", - "starkware.cairo.common.math.assert_lt_felt" - ], - "code": "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\nassert (ids.a % PRIME) < (ids.b % PRIME), \\\n f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'", - "flow_tracking_data": { - "ap_tracking": { "group": 3, "offset": 0 }, - "reference_ids": { - "starkware.cairo.common.math.assert_lt_felt.a": 5, - "starkware.cairo.common.math.assert_lt_felt.b": 6 - } - } - } - ], - "81": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.call_contract" - ], - "code": "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 4, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.call_contract.syscall_ptr": 7 - } - } - } - ], - "89": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.get_caller_address" - ], - "code": "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 5, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr": 8 - } - } - } - ], - "96": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.get_contract_address" - ], - "code": "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 6, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr": 9 - } - } - } - ], - "104": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.storage_read" - ], - "code": "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 7, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.storage_read.syscall_ptr": 10 - } - } - } - ], - "113": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.storage_write" - ], - "code": "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 8, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.storage_write.syscall_ptr": 11 - } - } - } - ], - "119": [ - { - "accessible_scopes": [ - "starkware.starknet.common.syscalls", - "starkware.starknet.common.syscalls.get_tx_info" - ], - "code": "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)", - "flow_tracking_data": { - "ap_tracking": { "group": 9, "offset": 1 }, - "reference_ids": { - "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": 12 - } - } - } - ], - "123": [ - { - "accessible_scopes": [ - "starkware.cairo.common.signature", - "starkware.cairo.common.signature.verify_ecdsa_signature" - ], - "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))", - "flow_tracking_data": { - "ap_tracking": { "group": 10, "offset": 0 }, - "reference_ids": { - "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr": 15, - "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r": 13, - "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s": 14 - } - } - } - ], - "128": [ - { - "accessible_scopes": [ - "starkware.cairo.common.math_cmp", - "starkware.cairo.common.math_cmp.is_le_felt" - ], - "code": "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1", - "flow_tracking_data": { - "ap_tracking": { "group": 11, "offset": 0 }, - "reference_ids": { - "starkware.cairo.common.math_cmp.is_le_felt.a": 16, - "starkware.cairo.common.math_cmp.is_le_felt.b": 17 - } - } - } - ], - "375": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.constructor" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 30, "offset": 35 }, - "reference_ids": {} - } - } - ], - "392": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.getPublicKey_encode_return" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 32, "offset": 0 }, - "reference_ids": {} - } - } - ], - "425": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.supportsInterface_encode_return" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 36, "offset": 0 }, - "reference_ids": {} - } - } - ], - "470": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.setPublicKey" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 40, "offset": 50 }, - "reference_ids": {} - } - } - ], - "491": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.isValidSignature_encode_return" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 42, "offset": 0 }, - "reference_ids": {} - } - } - ], - "579": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.__validate__" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 45, "offset": 77 }, - "reference_ids": {} - } - } - ], - "617": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.__validate_declare__" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 47, "offset": 63 }, - "reference_ids": {} - } - } - ], - "657": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.__validate_deploy__" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 49, "offset": 65 }, - "reference_ids": {} - } - } - ], - "680": [ - { - "accessible_scopes": [ - "__main__", - "__main__", - "__wrappers__", - "__wrappers__.__execute___encode_return" - ], - "code": "memory[ap] = segments.add()", - "flow_tracking_data": { - "ap_tracking": { "group": 52, "offset": 0 }, - "reference_ids": {} - } - } - ] - }, - "identifiers": { - "__main__.Account": { - "destination": "openzeppelin.account.library.Account", - "type": "alias" - }, - "__main__.AccountCallArray": { - "destination": "openzeppelin.account.library.AccountCallArray", - "type": "alias" - }, - "__main__.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "__main__.HashBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", - "type": "alias" - }, - "__main__.SignatureBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", - "type": "alias" - }, - "__main__.__execute__": { - "decorators": ["external"], - "pc": 668, - "type": "function" - }, - "__main__.__execute__.Args": { - "full_name": "__main__.__execute__.Args", - "members": { - "call_array": { - "cairo_type": "openzeppelin.account.library.AccountCallArray*", - "offset": 1 - }, - "call_array_len": { "cairo_type": "felt", "offset": 0 }, - "calldata": { "cairo_type": "felt*", "offset": 3 }, - "calldata_len": { "cairo_type": "felt", "offset": 2 } - }, - "size": 4, - "type": "struct" - }, - "__main__.__execute__.ImplicitArgs": { - "full_name": "__main__.__execute__.ImplicitArgs", - "members": { - "bitwise_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin*", - "offset": 3 - }, - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 4 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 5, - "type": "struct" - }, - "__main__.__execute__.Return": { - "cairo_type": "(response_len: felt, response: felt*)", - "type": "type_definition" - }, - "__main__.__execute__.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.__validate__": { - "decorators": ["external"], - "pc": 531, - "type": "function" - }, - "__main__.__validate__.Args": { - "full_name": "__main__.__validate__.Args", - "members": { - "call_array": { - "cairo_type": "openzeppelin.account.library.AccountCallArray*", - "offset": 1 - }, - "call_array_len": { "cairo_type": "felt", "offset": 0 }, - "calldata": { "cairo_type": "felt*", "offset": 3 }, - "calldata_len": { "cairo_type": "felt", "offset": 2 } - }, - "size": 4, - "type": "struct" - }, - "__main__.__validate__.ImplicitArgs": { - "full_name": "__main__.__validate__.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 3 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "__main__.__validate__.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.__validate__.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.__validate_declare__": { - "decorators": ["external"], - "pc": 590, - "type": "function" - }, - "__main__.__validate_declare__.Args": { - "full_name": "__main__.__validate_declare__.Args", - "members": { "class_hash": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "__main__.__validate_declare__.ImplicitArgs": { - "full_name": "__main__.__validate_declare__.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 3 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "__main__.__validate_declare__.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.__validate_declare__.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__main__.__validate_deploy__": { - "decorators": ["external"], - "pc": 628, - "type": "function" - }, - "__main__.__validate_deploy__.Args": { - "full_name": "__main__.__validate_deploy__.Args", - "members": { - "class_hash": { "cairo_type": "felt", "offset": 0 }, - "publicKey": { "cairo_type": "felt", "offset": 2 }, - "salt": { "cairo_type": "felt", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "__main__.__validate_deploy__.ImplicitArgs": { - "full_name": "__main__.__validate_deploy__.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 3 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "__main__.__validate_deploy__.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.__validate_deploy__.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.constructor": { - "decorators": ["constructor"], - "pc": 359, - "type": "function" - }, - "__main__.constructor.Args": { - "full_name": "__main__.constructor.Args", - "members": { "publicKey": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "__main__.constructor.ImplicitArgs": { - "full_name": "__main__.constructor.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "__main__.constructor.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.constructor.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.getPublicKey": { - "decorators": ["view"], - "pc": 386, - "type": "function" - }, - "__main__.getPublicKey.Args": { - "full_name": "__main__.getPublicKey.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__main__.getPublicKey.ImplicitArgs": { - "full_name": "__main__.getPublicKey.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "__main__.getPublicKey.Return": { - "cairo_type": "(publicKey: felt)", - "type": "type_definition" - }, - "__main__.getPublicKey.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.get_tx_info": { - "destination": "starkware.starknet.common.syscalls.get_tx_info", - "type": "alias" - }, - "__main__.isValidSignature": { - "decorators": ["view"], - "pc": 481, - "type": "function" - }, - "__main__.isValidSignature.Args": { - "full_name": "__main__.isValidSignature.Args", - "members": { - "hash": { "cairo_type": "felt", "offset": 0 }, - "signature": { "cairo_type": "felt*", "offset": 2 }, - "signature_len": { "cairo_type": "felt", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "__main__.isValidSignature.ImplicitArgs": { - "full_name": "__main__.isValidSignature.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 3 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "__main__.isValidSignature.Return": { - "cairo_type": "(isValid: felt)", - "type": "type_definition" - }, - "__main__.isValidSignature.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.setPublicKey": { - "decorators": ["external"], - "pc": 454, - "type": "function" - }, - "__main__.setPublicKey.Args": { - "full_name": "__main__.setPublicKey.Args", - "members": { "newPublicKey": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "__main__.setPublicKey.ImplicitArgs": { - "full_name": "__main__.setPublicKey.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "__main__.setPublicKey.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "__main__.setPublicKey.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__main__.supportsInterface": { - "decorators": ["view"], - "pc": 418, - "type": "function" - }, - "__main__.supportsInterface.Args": { - "full_name": "__main__.supportsInterface.Args", - "members": { "interfaceId": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "__main__.supportsInterface.ImplicitArgs": { - "full_name": "__main__.supportsInterface.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "__main__.supportsInterface.Return": { - "cairo_type": "(success: felt)", - "type": "type_definition" - }, - "__main__.supportsInterface.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__wrappers__.__execute__": { - "decorators": ["external"], - "pc": 699, - "type": "function" - }, - "__wrappers__.__execute__.Args": { - "full_name": "__wrappers__.__execute__.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__execute__.ImplicitArgs": { - "full_name": "__wrappers__.__execute__.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__execute__.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: starkware.cairo.common.cairo_builtins.BitwiseBuiltin*, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.__execute__.SIZEOF_LOCALS": { "type": "const", "value": 4 }, - "__wrappers__.__execute__.__wrapped_func": { - "destination": "__main__.__execute__", - "type": "alias" - }, - "__wrappers__.__execute___encode_return": { - "decorators": [], - "pc": 680, - "type": "function" - }, - "__wrappers__.__execute___encode_return.Args": { - "full_name": "__wrappers__.__execute___encode_return.Args", - "members": { - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "ret_value": { - "cairo_type": "(response_len: felt, response: felt*)", - "offset": 0 - } - }, - "size": 3, - "type": "struct" - }, - "__wrappers__.__execute___encode_return.ImplicitArgs": { - "full_name": "__wrappers__.__execute___encode_return.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__execute___encode_return.Return": { - "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", - "type": "type_definition" - }, - "__wrappers__.__execute___encode_return.SIZEOF_LOCALS": { - "type": "const", - "value": 3 - }, - "__wrappers__.__execute___encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.__validate__": { - "decorators": ["external"], - "pc": 548, - "type": "function" - }, - "__wrappers__.__validate__.Args": { - "full_name": "__wrappers__.__validate__.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate__.ImplicitArgs": { - "full_name": "__wrappers__.__validate__.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate__.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.__validate__.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__wrappers__.__validate__.__wrapped_func": { - "destination": "__main__.__validate__", - "type": "alias" - }, - "__wrappers__.__validate___encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.__validate_declare__": { - "decorators": ["external"], - "pc": 607, - "type": "function" - }, - "__wrappers__.__validate_declare__.Args": { - "full_name": "__wrappers__.__validate_declare__.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate_declare__.ImplicitArgs": { - "full_name": "__wrappers__.__validate_declare__.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate_declare__.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.__validate_declare__.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__wrappers__.__validate_declare__.__wrapped_func": { - "destination": "__main__.__validate_declare__", - "type": "alias" - }, - "__wrappers__.__validate_declare___encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.__validate_deploy__": { - "decorators": ["external"], - "pc": 645, - "type": "function" - }, - "__wrappers__.__validate_deploy__.Args": { - "full_name": "__wrappers__.__validate_deploy__.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate_deploy__.ImplicitArgs": { - "full_name": "__wrappers__.__validate_deploy__.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.__validate_deploy__.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.__validate_deploy__.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__wrappers__.__validate_deploy__.__wrapped_func": { - "destination": "__main__.__validate_deploy__", - "type": "alias" - }, - "__wrappers__.__validate_deploy___encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.constructor": { - "decorators": ["constructor"], - "pc": 366, - "type": "function" - }, - "__wrappers__.constructor.Args": { - "full_name": "__wrappers__.constructor.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.constructor.ImplicitArgs": { - "full_name": "__wrappers__.constructor.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.constructor.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.constructor.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__wrappers__.constructor.__wrapped_func": { - "destination": "__main__.constructor", - "type": "alias" - }, - "__wrappers__.constructor_encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.getPublicKey": { - "decorators": ["view"], - "pc": 401, - "type": "function" - }, - "__wrappers__.getPublicKey.Args": { - "full_name": "__wrappers__.getPublicKey.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.getPublicKey.ImplicitArgs": { - "full_name": "__wrappers__.getPublicKey.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.getPublicKey.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.getPublicKey.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__wrappers__.getPublicKey.__wrapped_func": { - "destination": "__main__.getPublicKey", - "type": "alias" - }, - "__wrappers__.getPublicKey_encode_return": { - "decorators": [], - "pc": 392, - "type": "function" - }, - "__wrappers__.getPublicKey_encode_return.Args": { - "full_name": "__wrappers__.getPublicKey_encode_return.Args", - "members": { - "range_check_ptr": { "cairo_type": "felt", "offset": 1 }, - "ret_value": { "cairo_type": "(publicKey: felt)", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "__wrappers__.getPublicKey_encode_return.ImplicitArgs": { - "full_name": "__wrappers__.getPublicKey_encode_return.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.getPublicKey_encode_return.Return": { - "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", - "type": "type_definition" - }, - "__wrappers__.getPublicKey_encode_return.SIZEOF_LOCALS": { - "type": "const", - "value": 1 - }, - "__wrappers__.getPublicKey_encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.isValidSignature": { - "decorators": ["view"], - "pc": 500, - "type": "function" - }, - "__wrappers__.isValidSignature.Args": { - "full_name": "__wrappers__.isValidSignature.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.isValidSignature.ImplicitArgs": { - "full_name": "__wrappers__.isValidSignature.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.isValidSignature.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.isValidSignature.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__wrappers__.isValidSignature.__wrapped_func": { - "destination": "__main__.isValidSignature", - "type": "alias" - }, - "__wrappers__.isValidSignature_encode_return": { - "decorators": [], - "pc": 491, - "type": "function" - }, - "__wrappers__.isValidSignature_encode_return.Args": { - "full_name": "__wrappers__.isValidSignature_encode_return.Args", - "members": { - "range_check_ptr": { "cairo_type": "felt", "offset": 1 }, - "ret_value": { "cairo_type": "(isValid: felt)", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "__wrappers__.isValidSignature_encode_return.ImplicitArgs": { - "full_name": "__wrappers__.isValidSignature_encode_return.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.isValidSignature_encode_return.Return": { - "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", - "type": "type_definition" - }, - "__wrappers__.isValidSignature_encode_return.SIZEOF_LOCALS": { - "type": "const", - "value": 1 - }, - "__wrappers__.isValidSignature_encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.setPublicKey": { - "decorators": ["external"], - "pc": 461, - "type": "function" - }, - "__wrappers__.setPublicKey.Args": { - "full_name": "__wrappers__.setPublicKey.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.setPublicKey.ImplicitArgs": { - "full_name": "__wrappers__.setPublicKey.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.setPublicKey.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.setPublicKey.SIZEOF_LOCALS": { "type": "const", "value": 0 }, - "__wrappers__.setPublicKey.__wrapped_func": { - "destination": "__main__.setPublicKey", - "type": "alias" - }, - "__wrappers__.setPublicKey_encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "__wrappers__.supportsInterface": { - "decorators": ["view"], - "pc": 434, - "type": "function" - }, - "__wrappers__.supportsInterface.Args": { - "full_name": "__wrappers__.supportsInterface.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.supportsInterface.ImplicitArgs": { - "full_name": "__wrappers__.supportsInterface.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.supportsInterface.Return": { - "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", - "type": "type_definition" - }, - "__wrappers__.supportsInterface.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "__wrappers__.supportsInterface.__wrapped_func": { - "destination": "__main__.supportsInterface", - "type": "alias" - }, - "__wrappers__.supportsInterface_encode_return": { - "decorators": [], - "pc": 425, - "type": "function" - }, - "__wrappers__.supportsInterface_encode_return.Args": { - "full_name": "__wrappers__.supportsInterface_encode_return.Args", - "members": { - "range_check_ptr": { "cairo_type": "felt", "offset": 1 }, - "ret_value": { "cairo_type": "(success: felt)", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "__wrappers__.supportsInterface_encode_return.ImplicitArgs": { - "full_name": "__wrappers__.supportsInterface_encode_return.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "__wrappers__.supportsInterface_encode_return.Return": { - "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", - "type": "type_definition" - }, - "__wrappers__.supportsInterface_encode_return.SIZEOF_LOCALS": { - "type": "const", - "value": 1 - }, - "__wrappers__.supportsInterface_encode_return.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "openzeppelin.account.library.Account": { "type": "namespace" }, - "openzeppelin.account.library.Account.Args": { - "full_name": "openzeppelin.account.library.Account.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account._execute_list": { - "decorators": [], - "pc": 301, - "type": "function" - }, - "openzeppelin.account.library.Account._execute_list.Args": { - "full_name": "openzeppelin.account.library.Account._execute_list.Args", - "members": { - "calls": { - "cairo_type": "openzeppelin.account.library.Call*", - "offset": 1 - }, - "calls_len": { "cairo_type": "felt", "offset": 0 }, - "response": { "cairo_type": "felt*", "offset": 2 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account._execute_list.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account._execute_list.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account._execute_list.Return": { - "cairo_type": "(response_len: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account._execute_list.SIZEOF_LOCALS": { - "type": "const", - "value": 3 - }, - "openzeppelin.account.library.Account._from_call_array_to_call": { - "decorators": [], - "pc": 335, - "type": "function" - }, - "openzeppelin.account.library.Account._from_call_array_to_call.Args": { - "full_name": "openzeppelin.account.library.Account._from_call_array_to_call.Args", - "members": { - "call_array": { - "cairo_type": "openzeppelin.account.library.AccountCallArray*", - "offset": 1 - }, - "call_array_len": { "cairo_type": "felt", "offset": 0 }, - "calldata": { "cairo_type": "felt*", "offset": 2 }, - "calls": { - "cairo_type": "openzeppelin.account.library.Call*", - "offset": 3 - } - }, - "size": 4, - "type": "struct" - }, - "openzeppelin.account.library.Account._from_call_array_to_call.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account._from_call_array_to_call.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account._from_call_array_to_call.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account._from_call_array_to_call.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.assert_only_self": { - "decorators": [], - "pc": 185, - "type": "function" - }, - "openzeppelin.account.library.Account.assert_only_self.Args": { - "full_name": "openzeppelin.account.library.Account.assert_only_self.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account.assert_only_self.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.assert_only_self.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account.assert_only_self.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.assert_only_self.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.execute": { - "decorators": [], - "pc": 254, - "type": "function" - }, - "openzeppelin.account.library.Account.execute.Args": { - "full_name": "openzeppelin.account.library.Account.execute.Args", - "members": { - "call_array": { - "cairo_type": "openzeppelin.account.library.AccountCallArray*", - "offset": 1 - }, - "call_array_len": { "cairo_type": "felt", "offset": 0 }, - "calldata": { "cairo_type": "felt*", "offset": 3 }, - "calldata_len": { "cairo_type": "felt", "offset": 2 } - }, - "size": 4, - "type": "struct" - }, - "openzeppelin.account.library.Account.execute.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.execute.ImplicitArgs", - "members": { - "bitwise_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin*", - "offset": 3 - }, - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 4 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 5, - "type": "struct" - }, - "openzeppelin.account.library.Account.execute.Return": { - "cairo_type": "(response_len: felt, response: felt*)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.execute.SIZEOF_LOCALS": { - "type": "const", - "value": 3 - }, - "openzeppelin.account.library.Account.get_public_key": { - "decorators": [], - "pc": 194, - "type": "function" - }, - "openzeppelin.account.library.Account.get_public_key.Args": { - "full_name": "openzeppelin.account.library.Account.get_public_key.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account.get_public_key.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.get_public_key.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account.get_public_key.Return": { - "cairo_type": "(public_key: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.get_public_key.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.initializer": { - "decorators": [], - "pc": 178, - "type": "function" - }, - "openzeppelin.account.library.Account.initializer.Args": { - "full_name": "openzeppelin.account.library.Account.initializer.Args", - "members": { "_public_key": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account.initializer.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.initializer.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account.initializer.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.initializer.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.is_valid_signature": { - "decorators": [], - "pc": 235, - "type": "function" - }, - "openzeppelin.account.library.Account.is_valid_signature.Args": { - "full_name": "openzeppelin.account.library.Account.is_valid_signature.Args", - "members": { - "hash": { "cairo_type": "felt", "offset": 0 }, - "signature": { "cairo_type": "felt*", "offset": 2 }, - "signature_len": { "cairo_type": "felt", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account.is_valid_signature.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.is_valid_signature.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 2 - }, - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 3 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "openzeppelin.account.library.Account.is_valid_signature.Return": { - "cairo_type": "(is_valid: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.is_valid_signature.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.set_public_key": { - "decorators": [], - "pc": 226, - "type": "function" - }, - "openzeppelin.account.library.Account.set_public_key.Args": { - "full_name": "openzeppelin.account.library.Account.set_public_key.Args", - "members": { "new_public_key": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account.set_public_key.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.set_public_key.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account.set_public_key.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.set_public_key.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account.supports_interface": { - "decorators": [], - "pc": 200, - "type": "function" - }, - "openzeppelin.account.library.Account.supports_interface.Args": { - "full_name": "openzeppelin.account.library.Account.supports_interface.Args", - "members": { "interface_id": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account.supports_interface.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account.supports_interface.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account.supports_interface.Return": { - "cairo_type": "(success: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account.supports_interface.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.AccountCallArray": { - "full_name": "openzeppelin.account.library.AccountCallArray", - "members": { - "data_len": { "cairo_type": "felt", "offset": 3 }, - "data_offset": { "cairo_type": "felt", "offset": 2 }, - "selector": { "cairo_type": "felt", "offset": 1 }, - "to": { "cairo_type": "felt", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key": { "type": "namespace" }, - "openzeppelin.account.library.Account_public_key.Args": { - "full_name": "openzeppelin.account.library.Account_public_key.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.HashBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", - "type": "alias" - }, - "openzeppelin.account.library.Account_public_key.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account_public_key.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account_public_key.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account_public_key.addr": { - "decorators": [], - "pc": 148, - "type": "function" - }, - "openzeppelin.account.library.Account_public_key.addr.Args": { - "full_name": "openzeppelin.account.library.Account_public_key.addr.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.addr.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account_public_key.addr.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 0 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.addr.Return": { - "cairo_type": "(res: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account_public_key.addr.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account_public_key.hash2": { - "destination": "starkware.cairo.common.hash.hash2", - "type": "alias" - }, - "openzeppelin.account.library.Account_public_key.normalize_address": { - "destination": "starkware.starknet.common.storage.normalize_address", - "type": "alias" - }, - "openzeppelin.account.library.Account_public_key.read": { - "decorators": [], - "pc": 153, - "type": "function" - }, - "openzeppelin.account.library.Account_public_key.read.Args": { - "full_name": "openzeppelin.account.library.Account_public_key.read.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.read.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account_public_key.read.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.read.Return": { - "cairo_type": "(public_key: felt)", - "type": "type_definition" - }, - "openzeppelin.account.library.Account_public_key.read.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.Account_public_key.storage_read": { - "destination": "starkware.starknet.common.syscalls.storage_read", - "type": "alias" - }, - "openzeppelin.account.library.Account_public_key.storage_write": { - "destination": "starkware.starknet.common.syscalls.storage_write", - "type": "alias" - }, - "openzeppelin.account.library.Account_public_key.write": { - "decorators": [], - "pc": 166, - "type": "function" - }, - "openzeppelin.account.library.Account_public_key.write.Args": { - "full_name": "openzeppelin.account.library.Account_public_key.write.Args", - "members": { "value": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.write.ImplicitArgs": { - "full_name": "openzeppelin.account.library.Account_public_key.write.ImplicitArgs", - "members": { - "pedersen_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", - "offset": 1 - }, - "range_check_ptr": { "cairo_type": "felt", "offset": 2 }, - "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "openzeppelin.account.library.Account_public_key.write.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "openzeppelin.account.library.Account_public_key.write.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "openzeppelin.account.library.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "openzeppelin.account.library.Call": { - "full_name": "openzeppelin.account.library.Call", - "members": { - "calldata": { "cairo_type": "felt*", "offset": 3 }, - "calldata_len": { "cairo_type": "felt", "offset": 2 }, - "selector": { "cairo_type": "felt", "offset": 1 }, - "to": { "cairo_type": "felt", "offset": 0 } - }, - "size": 4, - "type": "struct" - }, - "openzeppelin.account.library.FALSE": { - "destination": "starkware.cairo.common.bool.FALSE", - "type": "alias" - }, - "openzeppelin.account.library.HashBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", - "type": "alias" - }, - "openzeppelin.account.library.IACCOUNT_ID": { - "destination": "openzeppelin.utils.constants.library.IACCOUNT_ID", - "type": "alias" - }, - "openzeppelin.account.library.IERC165_ID": { - "destination": "openzeppelin.utils.constants.library.IERC165_ID", - "type": "alias" - }, - "openzeppelin.account.library.SignatureBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", - "type": "alias" - }, - "openzeppelin.account.library.TRANSACTION_VERSION": { - "destination": "openzeppelin.utils.constants.library.TRANSACTION_VERSION", - "type": "alias" - }, - "openzeppelin.account.library.TRUE": { - "destination": "starkware.cairo.common.bool.TRUE", - "type": "alias" - }, - "openzeppelin.account.library.Uint256": { - "destination": "starkware.cairo.common.uint256.Uint256", - "type": "alias" - }, - "openzeppelin.account.library.alloc": { - "destination": "starkware.cairo.common.alloc.alloc", - "type": "alias" - }, - "openzeppelin.account.library.call_contract": { - "destination": "starkware.starknet.common.syscalls.call_contract", - "type": "alias" - }, - "openzeppelin.account.library.get_caller_address": { - "destination": "starkware.starknet.common.syscalls.get_caller_address", - "type": "alias" - }, - "openzeppelin.account.library.get_contract_address": { - "destination": "starkware.starknet.common.syscalls.get_contract_address", - "type": "alias" - }, - "openzeppelin.account.library.get_fp_and_pc": { - "destination": "starkware.cairo.common.registers.get_fp_and_pc", - "type": "alias" - }, - "openzeppelin.account.library.get_tx_info": { - "destination": "starkware.starknet.common.syscalls.get_tx_info", - "type": "alias" - }, - "openzeppelin.account.library.is_le_felt": { - "destination": "starkware.cairo.common.math_cmp.is_le_felt", - "type": "alias" - }, - "openzeppelin.account.library.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "openzeppelin.account.library.split_felt": { - "destination": "starkware.cairo.common.math.split_felt", - "type": "alias" - }, - "openzeppelin.account.library.verify_ecdsa_signature": { - "destination": "starkware.cairo.common.signature.verify_ecdsa_signature", - "type": "alias" - }, - "openzeppelin.account.library.verify_eth_signature_uint256": { - "destination": "starkware.cairo.common.cairo_secp.signature.verify_eth_signature_uint256", - "type": "alias" - }, - "openzeppelin.utils.constants.library.DEFAULT_ADMIN_ROLE": { - "type": "const", - "value": 0 - }, - "openzeppelin.utils.constants.library.IACCESSCONTROL_ID": { - "type": "const", - "value": 2036718347 - }, - "openzeppelin.utils.constants.library.IACCOUNT_ID": { - "type": "const", - "value": 2792084853 - }, - "openzeppelin.utils.constants.library.IERC165_ID": { - "type": "const", - "value": 33540519 - }, - "openzeppelin.utils.constants.library.IERC721_ENUMERABLE_ID": { - "type": "const", - "value": 2014223715 - }, - "openzeppelin.utils.constants.library.IERC721_ID": { - "type": "const", - "value": 2158778573 - }, - "openzeppelin.utils.constants.library.IERC721_METADATA_ID": { - "type": "const", - "value": 1532892063 - }, - "openzeppelin.utils.constants.library.IERC721_RECEIVER_ID": { - "type": "const", - "value": 353073666 - }, - "openzeppelin.utils.constants.library.INVALID_ID": { - "type": "const", - "value": 4294967295 - }, - "openzeppelin.utils.constants.library.TRANSACTION_VERSION": { - "type": "const", - "value": 1 - }, - "openzeppelin.utils.constants.library.UINT8_MAX": { - "type": "const", - "value": 255 - }, - "starkware.cairo.common.alloc.alloc": { - "decorators": [], - "pc": 0, - "type": "function" - }, - "starkware.cairo.common.alloc.alloc.Args": { - "full_name": "starkware.cairo.common.alloc.alloc.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.cairo.common.alloc.alloc.ImplicitArgs": { - "full_name": "starkware.cairo.common.alloc.alloc.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.cairo.common.alloc.alloc.Return": { - "cairo_type": "(ptr: felt*)", - "type": "type_definition" - }, - "starkware.cairo.common.alloc.alloc.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.bitwise.ALL_ONES": { - "type": "const", - "value": -106710729501573572985208420194530329073740042555888586719234 - }, - "starkware.cairo.common.bitwise.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "starkware.cairo.common.bool.FALSE": { "type": "const", "value": 0 }, - "starkware.cairo.common.bool.TRUE": { "type": "const", "value": 1 }, - "starkware.cairo.common.cairo_builtins.BitwiseBuiltin": { - "full_name": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "members": { - "x": { "cairo_type": "felt", "offset": 0 }, - "x_and_y": { "cairo_type": "felt", "offset": 2 }, - "x_or_y": { "cairo_type": "felt", "offset": 4 }, - "x_xor_y": { "cairo_type": "felt", "offset": 3 }, - "y": { "cairo_type": "felt", "offset": 1 } - }, - "size": 5, - "type": "struct" - }, - "starkware.cairo.common.cairo_builtins.EcOpBuiltin": { - "full_name": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", - "members": { - "m": { "cairo_type": "felt", "offset": 4 }, - "p": { - "cairo_type": "starkware.cairo.common.ec_point.EcPoint", - "offset": 0 - }, - "q": { - "cairo_type": "starkware.cairo.common.ec_point.EcPoint", - "offset": 2 - }, - "r": { - "cairo_type": "starkware.cairo.common.ec_point.EcPoint", - "offset": 5 - } - }, - "size": 7, - "type": "struct" - }, - "starkware.cairo.common.cairo_builtins.EcPoint": { - "destination": "starkware.cairo.common.ec_point.EcPoint", - "type": "alias" - }, - "starkware.cairo.common.cairo_builtins.HashBuiltin": { - "full_name": "starkware.cairo.common.cairo_builtins.HashBuiltin", - "members": { - "result": { "cairo_type": "felt", "offset": 2 }, - "x": { "cairo_type": "felt", "offset": 0 }, - "y": { "cairo_type": "felt", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "starkware.cairo.common.cairo_builtins.KeccakBuiltin": { - "full_name": "starkware.cairo.common.cairo_builtins.KeccakBuiltin", - "members": { - "input": { - "cairo_type": "starkware.cairo.common.keccak_state.KeccakBuiltinState", - "offset": 0 - }, - "output": { - "cairo_type": "starkware.cairo.common.keccak_state.KeccakBuiltinState", - "offset": 8 - } - }, - "size": 16, - "type": "struct" - }, - "starkware.cairo.common.cairo_builtins.KeccakBuiltinState": { - "destination": "starkware.cairo.common.keccak_state.KeccakBuiltinState", - "type": "alias" - }, - "starkware.cairo.common.cairo_builtins.SignatureBuiltin": { - "full_name": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", - "members": { - "message": { "cairo_type": "felt", "offset": 1 }, - "pub_key": { "cairo_type": "felt", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.cairo_keccak.keccak.BLOCK_SIZE": { - "destination": "starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.BYTES_IN_WORD": { - "type": "const", - "value": 8 - }, - "starkware.cairo.common.cairo_keccak.keccak.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.KECCAK_CAPACITY_IN_WORDS": { - "type": "const", - "value": 8 - }, - "starkware.cairo.common.cairo_keccak.keccak.KECCAK_FULL_RATE_IN_BYTES": { - "type": "const", - "value": 136 - }, - "starkware.cairo.common.cairo_keccak.keccak.KECCAK_FULL_RATE_IN_WORDS": { - "type": "const", - "value": 17 - }, - "starkware.cairo.common.cairo_keccak.keccak.KECCAK_STATE_SIZE_FELTS": { - "type": "const", - "value": 25 - }, - "starkware.cairo.common.cairo_keccak.keccak.Uint256": { - "destination": "starkware.cairo.common.uint256.Uint256", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.alloc": { - "destination": "starkware.cairo.common.alloc.alloc", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.assert_lt": { - "destination": "starkware.cairo.common.math.assert_lt", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.assert_nn": { - "destination": "starkware.cairo.common.math.assert_nn", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.assert_nn_le": { - "destination": "starkware.cairo.common.math.assert_nn_le", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.assert_not_zero": { - "destination": "starkware.cairo.common.math.assert_not_zero", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.bitwise_and": { - "destination": "starkware.cairo.common.bitwise.bitwise_and", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.bitwise_or": { - "destination": "starkware.cairo.common.bitwise.bitwise_or", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.bitwise_xor": { - "destination": "starkware.cairo.common.bitwise.bitwise_xor", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.memcpy": { - "destination": "starkware.cairo.common.memcpy.memcpy", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.memset": { - "destination": "starkware.cairo.common.memset.memset", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.packed_keccak_func": { - "destination": "starkware.cairo.common.cairo_keccak.packed_keccak.packed_keccak_func", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.pow": { - "destination": "starkware.cairo.common.pow.pow", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.split_felt": { - "destination": "starkware.cairo.common.math.split_felt", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.uint256_reverse_endian": { - "destination": "starkware.cairo.common.uint256.uint256_reverse_endian", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem": { - "destination": "starkware.cairo.common.math.unsigned_div_rem", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.ALL_ONES": { - "type": "const", - "value": -106710729501573572985208420194530329073740042555888586719234 - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE": { - "type": "const", - "value": 3 - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.SHIFTS": { - "type": "const", - "value": 340282366920938463481821351505477763073 - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.alloc": { - "destination": "starkware.cairo.common.alloc.alloc", - "type": "alias" - }, - "starkware.cairo.common.cairo_keccak.packed_keccak.get_fp_and_pc": { - "destination": "starkware.cairo.common.registers.get_fp_and_pc", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.BASE": { - "destination": "starkware.cairo.common.cairo_secp.constants.BASE", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.BigInt3": { - "full_name": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "members": { - "d0": { "cairo_type": "felt", "offset": 0 }, - "d1": { "cairo_type": "felt", "offset": 1 }, - "d2": { "cairo_type": "felt", "offset": 2 } - }, - "size": 3, - "type": "struct" - }, - "starkware.cairo.common.cairo_secp.bigint.RC_BOUND": { - "destination": "starkware.cairo.common.math_cmp.RC_BOUND", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.Uint256": { - "destination": "starkware.cairo.common.uint256.Uint256", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3": { - "full_name": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", - "members": { - "d0": { "cairo_type": "felt", "offset": 0 }, - "d1": { "cairo_type": "felt", "offset": 1 }, - "d2": { "cairo_type": "felt", "offset": 2 } - }, - "size": 3, - "type": "struct" - }, - "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt5": { - "full_name": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt5", - "members": { - "d0": { "cairo_type": "felt", "offset": 0 }, - "d1": { "cairo_type": "felt", "offset": 1 }, - "d2": { "cairo_type": "felt", "offset": 2 }, - "d3": { "cairo_type": "felt", "offset": 3 }, - "d4": { "cairo_type": "felt", "offset": 4 } - }, - "size": 5, - "type": "struct" - }, - "starkware.cairo.common.cairo_secp.bigint.assert_nn": { - "destination": "starkware.cairo.common.math.assert_nn", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.assert_nn_le": { - "destination": "starkware.cairo.common.math.assert_nn_le", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.bigint.unsigned_div_rem": { - "destination": "starkware.cairo.common.math.unsigned_div_rem", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.constants.BASE": { - "type": "const", - "value": 77371252455336267181195264 - }, - "starkware.cairo.common.cairo_secp.constants.BETA": { - "type": "const", - "value": 7 - }, - "starkware.cairo.common.cairo_secp.constants.N0": { - "type": "const", - "value": 10428087374290690730508609 - }, - "starkware.cairo.common.cairo_secp.constants.N1": { - "type": "const", - "value": 77371252455330678278691517 - }, - "starkware.cairo.common.cairo_secp.constants.N2": { - "type": "const", - "value": 19342813113834066795298815 - }, - "starkware.cairo.common.cairo_secp.constants.P0": { - "type": "const", - "value": 77371252455336262886226991 - }, - "starkware.cairo.common.cairo_secp.constants.P1": { - "type": "const", - "value": 77371252455336267181195263 - }, - "starkware.cairo.common.cairo_secp.constants.P2": { - "type": "const", - "value": 19342813113834066795298815 - }, - "starkware.cairo.common.cairo_secp.constants.SECP_REM": { - "type": "const", - "value": 4294968273 - }, - "starkware.cairo.common.cairo_secp.ec.BigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.EcPoint": { - "full_name": "starkware.cairo.common.cairo_secp.ec.EcPoint", - "members": { - "x": { - "cairo_type": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "offset": 0 - }, - "y": { - "cairo_type": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "offset": 3 - } - }, - "size": 6, - "type": "struct" - }, - "starkware.cairo.common.cairo_secp.ec.UnreducedBigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.is_zero": { - "destination": "starkware.cairo.common.cairo_secp.field.is_zero", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.nondet_bigint3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.unreduced_mul": { - "destination": "starkware.cairo.common.cairo_secp.field.unreduced_mul", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.unreduced_sqr": { - "destination": "starkware.cairo.common.cairo_secp.field.unreduced_sqr", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.ec.verify_zero": { - "destination": "starkware.cairo.common.cairo_secp.field.verify_zero", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.BASE": { - "destination": "starkware.cairo.common.cairo_secp.constants.BASE", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.BigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.P0": { - "destination": "starkware.cairo.common.cairo_secp.constants.P0", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.P1": { - "destination": "starkware.cairo.common.cairo_secp.constants.P1", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.P2": { - "destination": "starkware.cairo.common.cairo_secp.constants.P2", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.SECP_REM": { - "destination": "starkware.cairo.common.cairo_secp.constants.SECP_REM", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.UnreducedBigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.assert_nn_le": { - "destination": "starkware.cairo.common.math.assert_nn_le", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.field.nondet_bigint3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.BASE": { - "destination": "starkware.cairo.common.cairo_secp.bigint.BASE", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.BETA": { - "destination": "starkware.cairo.common.cairo_secp.constants.BETA", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.BigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.EcPoint": { - "destination": "starkware.cairo.common.cairo_secp.ec.EcPoint", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.N0": { - "destination": "starkware.cairo.common.cairo_secp.constants.N0", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.N1": { - "destination": "starkware.cairo.common.cairo_secp.constants.N1", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.N2": { - "destination": "starkware.cairo.common.cairo_secp.constants.N2", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.RC_BOUND": { - "destination": "starkware.cairo.common.math_cmp.RC_BOUND", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.Uint256": { - "destination": "starkware.cairo.common.uint256.Uint256", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.UnreducedBigInt3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.alloc": { - "destination": "starkware.cairo.common.alloc.alloc", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.assert_nn": { - "destination": "starkware.cairo.common.math.assert_nn", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.assert_nn_le": { - "destination": "starkware.cairo.common.math.assert_nn_le", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.assert_not_zero": { - "destination": "starkware.cairo.common.math.assert_not_zero", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.bigint_mul": { - "destination": "starkware.cairo.common.cairo_secp.bigint.bigint_mul", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.bigint_to_uint256": { - "destination": "starkware.cairo.common.cairo_secp.bigint.bigint_to_uint256", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.ec_add": { - "destination": "starkware.cairo.common.cairo_secp.ec.ec_add", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.ec_mul": { - "destination": "starkware.cairo.common.cairo_secp.ec.ec_mul", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.ec_negate": { - "destination": "starkware.cairo.common.cairo_secp.ec.ec_negate", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.finalize_keccak": { - "destination": "starkware.cairo.common.cairo_keccak.keccak.finalize_keccak", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.keccak_uint256s_bigend": { - "destination": "starkware.cairo.common.cairo_keccak.keccak.keccak_uint256s_bigend", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.nondet_bigint3": { - "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.reduce": { - "destination": "starkware.cairo.common.cairo_secp.field.reduce", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.uint256_to_bigint": { - "destination": "starkware.cairo.common.cairo_secp.bigint.uint256_to_bigint", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.unreduced_mul": { - "destination": "starkware.cairo.common.cairo_secp.field.unreduced_mul", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.unreduced_sqr": { - "destination": "starkware.cairo.common.cairo_secp.field.unreduced_sqr", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.unsigned_div_rem": { - "destination": "starkware.cairo.common.math.unsigned_div_rem", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.validate_reduced_field_element": { - "destination": "starkware.cairo.common.cairo_secp.field.validate_reduced_field_element", - "type": "alias" - }, - "starkware.cairo.common.cairo_secp.signature.verify_zero": { - "destination": "starkware.cairo.common.cairo_secp.field.verify_zero", - "type": "alias" - }, - "starkware.cairo.common.dict_access.DictAccess": { - "full_name": "starkware.cairo.common.dict_access.DictAccess", - "members": { - "key": { "cairo_type": "felt", "offset": 0 }, - "new_value": { "cairo_type": "felt", "offset": 2 }, - "prev_value": { "cairo_type": "felt", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "starkware.cairo.common.ec.EcOpBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", - "type": "alias" - }, - "starkware.cairo.common.ec.EcPoint": { - "destination": "starkware.cairo.common.ec_point.EcPoint", - "type": "alias" - }, - "starkware.cairo.common.ec.StarkCurve": { "type": "namespace" }, - "starkware.cairo.common.ec.StarkCurve.ALPHA": { "type": "const", "value": 1 }, - "starkware.cairo.common.ec.StarkCurve.Args": { - "full_name": "starkware.cairo.common.ec.StarkCurve.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.cairo.common.ec.StarkCurve.BETA": { - "type": "const", - "value": -476910135076337975234679399815567221425937815956490878998147463828055613816 - }, - "starkware.cairo.common.ec.StarkCurve.GEN_X": { - "type": "const", - "value": 874739451078007766457464989774322083649278607533249481151382481072868806602 - }, - "starkware.cairo.common.ec.StarkCurve.GEN_Y": { - "type": "const", - "value": 152666792071518830868575557812948353041420400780739481342941381225525861407 - }, - "starkware.cairo.common.ec.StarkCurve.ImplicitArgs": { - "full_name": "starkware.cairo.common.ec.StarkCurve.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.cairo.common.ec.StarkCurve.ORDER": { - "type": "const", - "value": -96363463615509210819012598251359154898 - }, - "starkware.cairo.common.ec.StarkCurve.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.cairo.common.ec.StarkCurve.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.ec.is_quad_residue": { - "destination": "starkware.cairo.common.math.is_quad_residue", - "type": "alias" - }, - "starkware.cairo.common.ec_point.EcPoint": { - "full_name": "starkware.cairo.common.ec_point.EcPoint", - "members": { - "x": { "cairo_type": "felt", "offset": 0 }, - "y": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.hash.HashBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", - "type": "alias" - }, - "starkware.cairo.common.keccak_state.KeccakBuiltinState": { - "full_name": "starkware.cairo.common.keccak_state.KeccakBuiltinState", - "members": { - "s0": { "cairo_type": "felt", "offset": 0 }, - "s1": { "cairo_type": "felt", "offset": 1 }, - "s2": { "cairo_type": "felt", "offset": 2 }, - "s3": { "cairo_type": "felt", "offset": 3 }, - "s4": { "cairo_type": "felt", "offset": 4 }, - "s5": { "cairo_type": "felt", "offset": 5 }, - "s6": { "cairo_type": "felt", "offset": 6 }, - "s7": { "cairo_type": "felt", "offset": 7 } - }, - "size": 8, - "type": "struct" - }, - "starkware.cairo.common.math.FALSE": { - "destination": "starkware.cairo.common.bool.FALSE", - "type": "alias" - }, - "starkware.cairo.common.math.TRUE": { - "destination": "starkware.cairo.common.bool.TRUE", - "type": "alias" - }, - "starkware.cairo.common.math.assert_le_felt": { - "decorators": ["known_ap_change"], - "pc": 18, - "type": "function" - }, - "starkware.cairo.common.math.assert_le_felt.Args": { - "full_name": "starkware.cairo.common.math.assert_le_felt.Args", - "members": { - "a": { "cairo_type": "felt", "offset": 0 }, - "b": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.math.assert_le_felt.ImplicitArgs": { - "full_name": "starkware.cairo.common.math.assert_le_felt.ImplicitArgs", - "members": { "range_check_ptr": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.cairo.common.math.assert_le_felt.PRIME_OVER_2_HIGH": { - "type": "const", - "value": 5316911983139663648412552867652567041 - }, - "starkware.cairo.common.math.assert_le_felt.PRIME_OVER_3_HIGH": { - "type": "const", - "value": 3544607988759775765608368578435044694 - }, - "starkware.cairo.common.math.assert_le_felt.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.cairo.common.math.assert_le_felt.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.math.assert_le_felt.a": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math.assert_le_felt.a", - "references": [ - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-4), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math.assert_le_felt.b": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math.assert_le_felt.b", - "references": [ - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math.assert_le_felt.range_check_ptr": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math.assert_le_felt.range_check_ptr", - "references": [ - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-5), felt*)]" - }, - { - "ap_tracking_data": { "group": 2, "offset": 8 }, - "pc": 28, - "value": "cast([fp + (-5)] + 4, felt)" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math.assert_le_felt.skip_exclude_a": { - "pc": 42, - "type": "label" - }, - "starkware.cairo.common.math.assert_le_felt.skip_exclude_b_minus_a": { - "pc": 54, - "type": "label" - }, - "starkware.cairo.common.math.assert_lt_felt": { - "decorators": ["known_ap_change"], - "pc": 63, - "type": "function" - }, - "starkware.cairo.common.math.assert_lt_felt.Args": { - "full_name": "starkware.cairo.common.math.assert_lt_felt.Args", - "members": { - "a": { "cairo_type": "felt", "offset": 0 }, - "b": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.math.assert_lt_felt.ImplicitArgs": { - "full_name": "starkware.cairo.common.math.assert_lt_felt.ImplicitArgs", - "members": { "range_check_ptr": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.cairo.common.math.assert_lt_felt.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.cairo.common.math.assert_lt_felt.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.math.assert_lt_felt.a": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math.assert_lt_felt.a", - "references": [ - { - "ap_tracking_data": { "group": 3, "offset": 0 }, - "pc": 63, - "value": "[cast(fp + (-4), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math.assert_lt_felt.b": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math.assert_lt_felt.b", - "references": [ - { - "ap_tracking_data": { "group": 3, "offset": 0 }, - "pc": 63, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math_cmp.RC_BOUND": { - "type": "const", - "value": 340282366920938463463374607431768211456 - }, - "starkware.cairo.common.math_cmp.assert_le_felt": { - "destination": "starkware.cairo.common.math.assert_le_felt", - "type": "alias" - }, - "starkware.cairo.common.math_cmp.assert_lt_felt": { - "destination": "starkware.cairo.common.math.assert_lt_felt", - "type": "alias" - }, - "starkware.cairo.common.math_cmp.is_le_felt": { - "decorators": ["known_ap_change"], - "pc": 128, - "type": "function" - }, - "starkware.cairo.common.math_cmp.is_le_felt.Args": { - "full_name": "starkware.cairo.common.math_cmp.is_le_felt.Args", - "members": { - "a": { "cairo_type": "felt", "offset": 0 }, - "b": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.math_cmp.is_le_felt.ImplicitArgs": { - "full_name": "starkware.cairo.common.math_cmp.is_le_felt.ImplicitArgs", - "members": { "range_check_ptr": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.cairo.common.math_cmp.is_le_felt.Return": { - "cairo_type": "felt", - "type": "type_definition" - }, - "starkware.cairo.common.math_cmp.is_le_felt.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.math_cmp.is_le_felt.a": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math_cmp.is_le_felt.a", - "references": [ - { - "ap_tracking_data": { "group": 11, "offset": 0 }, - "pc": 128, - "value": "[cast(fp + (-4), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math_cmp.is_le_felt.b": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.math_cmp.is_le_felt.b", - "references": [ - { - "ap_tracking_data": { "group": 11, "offset": 0 }, - "pc": 128, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.math_cmp.is_le_felt.not_le": { - "pc": 140, - "type": "label" - }, - "starkware.cairo.common.memcpy.memcpy": { - "decorators": [], - "pc": 3, - "type": "function" - }, - "starkware.cairo.common.memcpy.memcpy.Args": { - "full_name": "starkware.cairo.common.memcpy.memcpy.Args", - "members": { - "dst": { "cairo_type": "felt*", "offset": 0 }, - "len": { "cairo_type": "felt", "offset": 2 }, - "src": { "cairo_type": "felt*", "offset": 1 } - }, - "size": 3, - "type": "struct" - }, - "starkware.cairo.common.memcpy.memcpy.ImplicitArgs": { - "full_name": "starkware.cairo.common.memcpy.memcpy.ImplicitArgs", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.cairo.common.memcpy.memcpy.LoopFrame": { - "full_name": "starkware.cairo.common.memcpy.memcpy.LoopFrame", - "members": { - "dst": { "cairo_type": "felt*", "offset": 0 }, - "src": { "cairo_type": "felt*", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.memcpy.memcpy.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.cairo.common.memcpy.memcpy.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.memcpy.memcpy.continue_copying": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.memcpy.memcpy.continue_copying", - "references": [ - { - "ap_tracking_data": { "group": 1, "offset": 3 }, - "pc": 10, - "value": "[cast(ap, felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.memcpy.memcpy.len": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.memcpy.memcpy.len", - "references": [ - { - "ap_tracking_data": { "group": 1, "offset": 0 }, - "pc": 3, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.memcpy.memcpy.loop": { "pc": 8, "type": "label" }, - "starkware.cairo.common.pow.assert_le": { - "destination": "starkware.cairo.common.math.assert_le", - "type": "alias" - }, - "starkware.cairo.common.pow.get_ap": { - "destination": "starkware.cairo.common.registers.get_ap", - "type": "alias" - }, - "starkware.cairo.common.pow.get_fp_and_pc": { - "destination": "starkware.cairo.common.registers.get_fp_and_pc", - "type": "alias" - }, - "starkware.cairo.common.registers.get_ap": { - "destination": "starkware.cairo.lang.compiler.lib.registers.get_ap", - "type": "alias" - }, - "starkware.cairo.common.registers.get_fp_and_pc": { - "destination": "starkware.cairo.lang.compiler.lib.registers.get_fp_and_pc", - "type": "alias" - }, - "starkware.cairo.common.signature.EcOpBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", - "type": "alias" - }, - "starkware.cairo.common.signature.EcPoint": { - "destination": "starkware.cairo.common.ec_point.EcPoint", - "type": "alias" - }, - "starkware.cairo.common.signature.FALSE": { - "destination": "starkware.cairo.common.bool.FALSE", - "type": "alias" - }, - "starkware.cairo.common.signature.SignatureBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", - "type": "alias" - }, - "starkware.cairo.common.signature.StarkCurve": { - "destination": "starkware.cairo.common.ec.StarkCurve", - "type": "alias" - }, - "starkware.cairo.common.signature.TRUE": { - "destination": "starkware.cairo.common.bool.TRUE", - "type": "alias" - }, - "starkware.cairo.common.signature.ec_add": { - "destination": "starkware.cairo.common.ec.ec_add", - "type": "alias" - }, - "starkware.cairo.common.signature.ec_mul": { - "destination": "starkware.cairo.common.ec.ec_mul", - "type": "alias" - }, - "starkware.cairo.common.signature.ec_sub": { - "destination": "starkware.cairo.common.ec.ec_sub", - "type": "alias" - }, - "starkware.cairo.common.signature.is_x_on_curve": { - "destination": "starkware.cairo.common.ec.is_x_on_curve", - "type": "alias" - }, - "starkware.cairo.common.signature.recover_y": { - "destination": "starkware.cairo.common.ec.recover_y", - "type": "alias" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature": { - "decorators": [], - "pc": 123, - "type": "function" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.Args": { - "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.Args", - "members": { - "message": { "cairo_type": "felt", "offset": 0 }, - "public_key": { "cairo_type": "felt", "offset": 1 }, - "signature_r": { "cairo_type": "felt", "offset": 2 }, - "signature_s": { "cairo_type": "felt", "offset": 3 } - }, - "size": 4, - "type": "struct" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.ImplicitArgs": { - "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.ImplicitArgs", - "members": { - "ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr": { - "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", - "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr", - "references": [ - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-7), starkware.cairo.common.cairo_builtins.SignatureBuiltin**)]" - }, - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 125, - "value": "cast([fp + (-7)] + 2, starkware.cairo.common.cairo_builtins.SignatureBuiltin*)" - } - ], - "type": "reference" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r", - "references": [ - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-4), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s": { - "cairo_type": "felt", - "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s", - "references": [ - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-3), felt*)]" - } - ], - "type": "reference" - }, - "starkware.cairo.common.uint256.ALL_ONES": { - "type": "const", - "value": 340282366920938463463374607431768211455 - }, - "starkware.cairo.common.uint256.BitwiseBuiltin": { - "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", - "type": "alias" - }, - "starkware.cairo.common.uint256.HALF_SHIFT": { - "type": "const", - "value": 18446744073709551616 - }, - "starkware.cairo.common.uint256.SHIFT": { - "type": "const", - "value": 340282366920938463463374607431768211456 - }, - "starkware.cairo.common.uint256.Uint256": { - "full_name": "starkware.cairo.common.uint256.Uint256", - "members": { - "high": { "cairo_type": "felt", "offset": 1 }, - "low": { "cairo_type": "felt", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "starkware.cairo.common.uint256.assert_in_range": { - "destination": "starkware.cairo.common.math.assert_in_range", - "type": "alias" - }, - "starkware.cairo.common.uint256.assert_le": { - "destination": "starkware.cairo.common.math.assert_le", - "type": "alias" - }, - "starkware.cairo.common.uint256.assert_nn_le": { - "destination": "starkware.cairo.common.math.assert_nn_le", - "type": "alias" - }, - "starkware.cairo.common.uint256.assert_not_zero": { - "destination": "starkware.cairo.common.math.assert_not_zero", - "type": "alias" - }, - "starkware.cairo.common.uint256.bitwise_and": { - "destination": "starkware.cairo.common.bitwise.bitwise_and", - "type": "alias" - }, - "starkware.cairo.common.uint256.bitwise_or": { - "destination": "starkware.cairo.common.bitwise.bitwise_or", - "type": "alias" - }, - "starkware.cairo.common.uint256.bitwise_xor": { - "destination": "starkware.cairo.common.bitwise.bitwise_xor", - "type": "alias" - }, - "starkware.cairo.common.uint256.get_ap": { - "destination": "starkware.cairo.common.registers.get_ap", - "type": "alias" - }, - "starkware.cairo.common.uint256.get_fp_and_pc": { - "destination": "starkware.cairo.common.registers.get_fp_and_pc", - "type": "alias" - }, - "starkware.cairo.common.uint256.is_le": { - "destination": "starkware.cairo.common.math_cmp.is_le", - "type": "alias" - }, - "starkware.cairo.common.uint256.pow": { - "destination": "starkware.cairo.common.pow.pow", - "type": "alias" - }, - "starkware.starknet.common.storage.ADDR_BOUND": { - "type": "const", - "value": -106710729501573572985208420194530329073740042555888586719489 - }, - "starkware.starknet.common.storage.MAX_STORAGE_ITEM_SIZE": { - "type": "const", - "value": 256 - }, - "starkware.starknet.common.storage.assert_250_bit": { - "destination": "starkware.cairo.common.math.assert_250_bit", - "type": "alias" - }, - "starkware.starknet.common.syscalls.CALL_CONTRACT_SELECTOR": { - "type": "const", - "value": 20853273475220472486191784820 - }, - "starkware.starknet.common.syscalls.CallContract": { - "full_name": "starkware.starknet.common.syscalls.CallContract", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", - "offset": 5 - } - }, - "size": 7, - "type": "struct" - }, - "starkware.starknet.common.syscalls.CallContractRequest": { - "full_name": "starkware.starknet.common.syscalls.CallContractRequest", - "members": { - "calldata": { "cairo_type": "felt*", "offset": 4 }, - "calldata_size": { "cairo_type": "felt", "offset": 3 }, - "contract_address": { "cairo_type": "felt", "offset": 1 }, - "function_selector": { "cairo_type": "felt", "offset": 2 }, - "selector": { "cairo_type": "felt", "offset": 0 } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.CallContractResponse": { - "full_name": "starkware.starknet.common.syscalls.CallContractResponse", - "members": { - "retdata": { "cairo_type": "felt*", "offset": 1 }, - "retdata_size": { "cairo_type": "felt", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DELEGATE_CALL_SELECTOR": { - "type": "const", - "value": 21167594061783206823196716140 - }, - "starkware.starknet.common.syscalls.DELEGATE_L1_HANDLER_SELECTOR": { - "type": "const", - "value": 23274015802972845247556842986379118667122 - }, - "starkware.starknet.common.syscalls.DEPLOY_SELECTOR": { - "type": "const", - "value": 75202468540281 - }, - "starkware.starknet.common.syscalls.Deploy": { - "full_name": "starkware.starknet.common.syscalls.Deploy", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.DeployRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.DeployResponse", - "offset": 6 - } - }, - "size": 9, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DeployRequest": { - "full_name": "starkware.starknet.common.syscalls.DeployRequest", - "members": { - "class_hash": { "cairo_type": "felt", "offset": 1 }, - "constructor_calldata": { "cairo_type": "felt*", "offset": 4 }, - "constructor_calldata_size": { "cairo_type": "felt", "offset": 3 }, - "contract_address_salt": { "cairo_type": "felt", "offset": 2 }, - "deploy_from_zero": { "cairo_type": "felt", "offset": 5 }, - "selector": { "cairo_type": "felt", "offset": 0 } - }, - "size": 6, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DeployResponse": { - "full_name": "starkware.starknet.common.syscalls.DeployResponse", - "members": { - "constructor_retdata": { "cairo_type": "felt*", "offset": 2 }, - "constructor_retdata_size": { "cairo_type": "felt", "offset": 1 }, - "contract_address": { "cairo_type": "felt", "offset": 0 } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.DictAccess": { - "destination": "starkware.cairo.common.dict_access.DictAccess", - "type": "alias" - }, - "starkware.starknet.common.syscalls.EMIT_EVENT_SELECTOR": { - "type": "const", - "value": 1280709301550335749748 - }, - "starkware.starknet.common.syscalls.EmitEvent": { - "full_name": "starkware.starknet.common.syscalls.EmitEvent", - "members": { - "data": { "cairo_type": "felt*", "offset": 4 }, - "data_len": { "cairo_type": "felt", "offset": 3 }, - "keys": { "cairo_type": "felt*", "offset": 2 }, - "keys_len": { "cairo_type": "felt", "offset": 1 }, - "selector": { "cairo_type": "felt", "offset": 0 } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GET_BLOCK_NUMBER_SELECTOR": { - "type": "const", - "value": 1448089106835523001438702345020786 - }, - "starkware.starknet.common.syscalls.GET_BLOCK_TIMESTAMP_SELECTOR": { - "type": "const", - "value": 24294903732626645868215235778792757751152 - }, - "starkware.starknet.common.syscalls.GET_CALLER_ADDRESS_SELECTOR": { - "type": "const", - "value": 94901967781393078444254803017658102643 - }, - "starkware.starknet.common.syscalls.GET_CONTRACT_ADDRESS_SELECTOR": { - "type": "const", - "value": 6219495360805491471215297013070624192820083 - }, - "starkware.starknet.common.syscalls.GET_SEQUENCER_ADDRESS_SELECTOR": { - "type": "const", - "value": 1592190833581991703053805829594610833820054387 - }, - "starkware.starknet.common.syscalls.GET_TX_INFO_SELECTOR": { - "type": "const", - "value": 1317029390204112103023 - }, - "starkware.starknet.common.syscalls.GET_TX_SIGNATURE_SELECTOR": { - "type": "const", - "value": 1448089128652340074717162277007973 - }, - "starkware.starknet.common.syscalls.GetBlockNumber": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumber", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockNumberRequest": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumberRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockNumberResponse": { - "full_name": "starkware.starknet.common.syscalls.GetBlockNumberResponse", - "members": { "block_number": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestamp": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestamp", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestampRequest": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetBlockTimestampResponse": { - "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", - "members": { "block_timestamp": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddress": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddressRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetCallerAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetCallerAddressResponse", - "members": { "caller_address": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddress": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddressRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetContractAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetContractAddressResponse", - "members": { "contract_address": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddress": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddress", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddressRequest": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetSequencerAddressResponse": { - "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", - "members": { "sequencer_address": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfo": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfo", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoResponse", - "offset": 1 - } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfoRequest": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfoRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxInfoResponse": { - "full_name": "starkware.starknet.common.syscalls.GetTxInfoResponse", - "members": { - "tx_info": { - "cairo_type": "starkware.starknet.common.syscalls.TxInfo*", - "offset": 0 - } - }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignature": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignature", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureResponse", - "offset": 1 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignatureRequest": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignatureRequest", - "members": { "selector": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.GetTxSignatureResponse": { - "full_name": "starkware.starknet.common.syscalls.GetTxSignatureResponse", - "members": { - "signature": { "cairo_type": "felt*", "offset": 1 }, - "signature_len": { "cairo_type": "felt", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.LIBRARY_CALL_L1_HANDLER_SELECTOR": { - "type": "const", - "value": 436233452754198157705746250789557519228244616562 - }, - "starkware.starknet.common.syscalls.LIBRARY_CALL_SELECTOR": { - "type": "const", - "value": 92376026794327011772951660 - }, - "starkware.starknet.common.syscalls.LibraryCall": { - "full_name": "starkware.starknet.common.syscalls.LibraryCall", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.LibraryCallRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", - "offset": 5 - } - }, - "size": 7, - "type": "struct" - }, - "starkware.starknet.common.syscalls.LibraryCallRequest": { - "full_name": "starkware.starknet.common.syscalls.LibraryCallRequest", - "members": { - "calldata": { "cairo_type": "felt*", "offset": 4 }, - "calldata_size": { "cairo_type": "felt", "offset": 3 }, - "class_hash": { "cairo_type": "felt", "offset": 1 }, - "function_selector": { "cairo_type": "felt", "offset": 2 }, - "selector": { "cairo_type": "felt", "offset": 0 } - }, - "size": 5, - "type": "struct" - }, - "starkware.starknet.common.syscalls.SEND_MESSAGE_TO_L1_SELECTOR": { - "type": "const", - "value": 433017908768303439907196859243777073 - }, - "starkware.starknet.common.syscalls.STORAGE_READ_SELECTOR": { - "type": "const", - "value": 100890693370601760042082660 - }, - "starkware.starknet.common.syscalls.STORAGE_WRITE_SELECTOR": { - "type": "const", - "value": 25828017502874050592466629733 - }, - "starkware.starknet.common.syscalls.SendMessageToL1SysCall": { - "full_name": "starkware.starknet.common.syscalls.SendMessageToL1SysCall", - "members": { - "payload_ptr": { "cairo_type": "felt*", "offset": 3 }, - "payload_size": { "cairo_type": "felt", "offset": 2 }, - "selector": { "cairo_type": "felt", "offset": 0 }, - "to_address": { "cairo_type": "felt", "offset": 1 } - }, - "size": 4, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageRead": { - "full_name": "starkware.starknet.common.syscalls.StorageRead", - "members": { - "request": { - "cairo_type": "starkware.starknet.common.syscalls.StorageReadRequest", - "offset": 0 - }, - "response": { - "cairo_type": "starkware.starknet.common.syscalls.StorageReadResponse", - "offset": 2 - } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageReadRequest": { - "full_name": "starkware.starknet.common.syscalls.StorageReadRequest", - "members": { - "address": { "cairo_type": "felt", "offset": 1 }, - "selector": { "cairo_type": "felt", "offset": 0 } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageReadResponse": { - "full_name": "starkware.starknet.common.syscalls.StorageReadResponse", - "members": { "value": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.StorageWrite": { - "full_name": "starkware.starknet.common.syscalls.StorageWrite", - "members": { - "address": { "cairo_type": "felt", "offset": 1 }, - "selector": { "cairo_type": "felt", "offset": 0 }, - "value": { "cairo_type": "felt", "offset": 2 } - }, - "size": 3, - "type": "struct" - }, - "starkware.starknet.common.syscalls.TxInfo": { - "full_name": "starkware.starknet.common.syscalls.TxInfo", - "members": { - "account_contract_address": { "cairo_type": "felt", "offset": 1 }, - "chain_id": { "cairo_type": "felt", "offset": 6 }, - "max_fee": { "cairo_type": "felt", "offset": 2 }, - "nonce": { "cairo_type": "felt", "offset": 7 }, - "signature": { "cairo_type": "felt*", "offset": 4 }, - "signature_len": { "cairo_type": "felt", "offset": 3 }, - "transaction_hash": { "cairo_type": "felt", "offset": 5 }, - "version": { "cairo_type": "felt", "offset": 0 } - }, - "size": 8, - "type": "struct" - }, - "starkware.starknet.common.syscalls.call_contract": { - "decorators": [], - "pc": 74, - "type": "function" - }, - "starkware.starknet.common.syscalls.call_contract.Args": { - "full_name": "starkware.starknet.common.syscalls.call_contract.Args", - "members": { - "calldata": { "cairo_type": "felt*", "offset": 3 }, - "calldata_size": { "cairo_type": "felt", "offset": 2 }, - "contract_address": { "cairo_type": "felt", "offset": 0 }, - "function_selector": { "cairo_type": "felt", "offset": 1 } - }, - "size": 4, - "type": "struct" - }, - "starkware.starknet.common.syscalls.call_contract.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.call_contract.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.call_contract.Return": { - "cairo_type": "(retdata_size: felt, retdata: felt*)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.call_contract.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.call_contract.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.call_contract.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 4, "offset": 0 }, - "pc": 74, - "value": "[cast(fp + (-7), felt**)]" - }, - { - "ap_tracking_data": { "group": 4, "offset": 1 }, - "pc": 81, - "value": "cast([fp + (-7)] + 7, felt*)" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.get_caller_address": { - "decorators": [], - "pc": 86, - "type": "function" - }, - "starkware.starknet.common.syscalls.get_caller_address.Args": { - "full_name": "starkware.starknet.common.syscalls.get_caller_address.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_caller_address.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.get_caller_address.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_caller_address.Return": { - "cairo_type": "(caller_address: felt)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.get_caller_address.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 5, "offset": 0 }, - "pc": 86, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 5, "offset": 1 }, - "pc": 89, - "value": "cast([fp + (-3)] + 2, felt*)" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.get_contract_address": { - "decorators": [], - "pc": 93, - "type": "function" - }, - "starkware.starknet.common.syscalls.get_contract_address.Args": { - "full_name": "starkware.starknet.common.syscalls.get_contract_address.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_contract_address.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.get_contract_address.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_contract_address.Return": { - "cairo_type": "(contract_address: felt)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.get_contract_address.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 6, "offset": 0 }, - "pc": 93, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 6, "offset": 1 }, - "pc": 96, - "value": "cast([fp + (-3)] + 2, felt*)" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.get_tx_info": { - "decorators": [], - "pc": 116, - "type": "function" - }, - "starkware.starknet.common.syscalls.get_tx_info.Args": { - "full_name": "starkware.starknet.common.syscalls.get_tx_info.Args", - "members": {}, - "size": 0, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_tx_info.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.get_tx_info.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.get_tx_info.Return": { - "cairo_type": "(tx_info: starkware.starknet.common.syscalls.TxInfo*)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.get_tx_info.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 9, "offset": 0 }, - "pc": 116, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 9, "offset": 1 }, - "pc": 119, - "value": "cast([fp + (-3)] + 2, felt*)" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.storage_read": { - "decorators": [], - "pc": 100, - "type": "function" - }, - "starkware.starknet.common.syscalls.storage_read.Args": { - "full_name": "starkware.starknet.common.syscalls.storage_read.Args", - "members": { "address": { "cairo_type": "felt", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.storage_read.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.storage_read.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.storage_read.Return": { - "cairo_type": "(value: felt)", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.storage_read.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.storage_read.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.storage_read.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 7, "offset": 0 }, - "pc": 100, - "value": "[cast(fp + (-4), felt**)]" - }, - { - "ap_tracking_data": { "group": 7, "offset": 1 }, - "pc": 104, - "value": "cast([fp + (-4)] + 3, felt*)" - } - ], - "type": "reference" - }, - "starkware.starknet.common.syscalls.storage_write": { - "decorators": [], - "pc": 108, - "type": "function" - }, - "starkware.starknet.common.syscalls.storage_write.Args": { - "full_name": "starkware.starknet.common.syscalls.storage_write.Args", - "members": { - "address": { "cairo_type": "felt", "offset": 0 }, - "value": { "cairo_type": "felt", "offset": 1 } - }, - "size": 2, - "type": "struct" - }, - "starkware.starknet.common.syscalls.storage_write.ImplicitArgs": { - "full_name": "starkware.starknet.common.syscalls.storage_write.ImplicitArgs", - "members": { "syscall_ptr": { "cairo_type": "felt*", "offset": 0 } }, - "size": 1, - "type": "struct" - }, - "starkware.starknet.common.syscalls.storage_write.Return": { - "cairo_type": "()", - "type": "type_definition" - }, - "starkware.starknet.common.syscalls.storage_write.SIZEOF_LOCALS": { - "type": "const", - "value": 0 - }, - "starkware.starknet.common.syscalls.storage_write.syscall_ptr": { - "cairo_type": "felt*", - "full_name": "starkware.starknet.common.syscalls.storage_write.syscall_ptr", - "references": [ - { - "ap_tracking_data": { "group": 8, "offset": 0 }, - "pc": 108, - "value": "[cast(fp + (-5), felt**)]" - }, - { - "ap_tracking_data": { "group": 8, "offset": 1 }, - "pc": 113, - "value": "cast([fp + (-5)] + 3, felt*)" - } - ], - "type": "reference" - } - }, - "main_scope": "__main__", - "prime": "0x800000000000011000000000000000000000000000000000000000000000001", - "reference_manager": { - "references": [ - { - "ap_tracking_data": { "group": 1, "offset": 0 }, - "pc": 3, - "value": "[cast(fp + (-3), felt*)]" - }, - { - "ap_tracking_data": { "group": 1, "offset": 3 }, - "pc": 10, - "value": "[cast(ap, felt*)]" - }, - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-4), felt*)]" - }, - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-3), felt*)]" - }, - { - "ap_tracking_data": { "group": 2, "offset": 0 }, - "pc": 18, - "value": "[cast(fp + (-5), felt*)]" - }, - { - "ap_tracking_data": { "group": 3, "offset": 0 }, - "pc": 63, - "value": "[cast(fp + (-4), felt*)]" - }, - { - "ap_tracking_data": { "group": 3, "offset": 0 }, - "pc": 63, - "value": "[cast(fp + (-3), felt*)]" - }, - { - "ap_tracking_data": { "group": 4, "offset": 0 }, - "pc": 74, - "value": "[cast(fp + (-7), felt**)]" - }, - { - "ap_tracking_data": { "group": 5, "offset": 0 }, - "pc": 86, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 6, "offset": 0 }, - "pc": 93, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 7, "offset": 0 }, - "pc": 100, - "value": "[cast(fp + (-4), felt**)]" - }, - { - "ap_tracking_data": { "group": 8, "offset": 0 }, - "pc": 108, - "value": "[cast(fp + (-5), felt**)]" - }, - { - "ap_tracking_data": { "group": 9, "offset": 0 }, - "pc": 116, - "value": "[cast(fp + (-3), felt**)]" - }, - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-4), felt*)]" - }, - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-3), felt*)]" - }, - { - "ap_tracking_data": { "group": 10, "offset": 0 }, - "pc": 123, - "value": "[cast(fp + (-7), starkware.cairo.common.cairo_builtins.SignatureBuiltin**)]" - }, - { - "ap_tracking_data": { "group": 11, "offset": 0 }, - "pc": 128, - "value": "[cast(fp + (-4), felt*)]" - }, - { - "ap_tracking_data": { "group": 11, "offset": 0 }, - "pc": 128, - "value": "[cast(fp + (-3), felt*)]" - } - ] - } - } + "abi": [ + { + "members": [ + { + "name": "to", + "offset": 0, + "type": "felt" + }, + { + "name": "selector", + "offset": 1, + "type": "felt" + }, + { + "name": "data_offset", + "offset": 2, + "type": "felt" + }, + { + "name": "data_len", + "offset": 3, + "type": "felt" + } + ], + "name": "AccountCallArray", + "size": 4, + "type": "struct" + }, + { + "inputs": [ + { + "name": "publicKey", + "type": "felt" + } + ], + "name": "constructor", + "outputs": [], + "type": "constructor" + }, + { + "inputs": [], + "name": "getPublicKey", + "outputs": [ + { + "name": "publicKey", + "type": "felt" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "interfaceId", + "type": "felt" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "name": "success", + "type": "felt" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "newPublicKey", + "type": "felt" + } + ], + "name": "setPublicKey", + "outputs": [], + "type": "function" + }, + { + "inputs": [ + { + "name": "hash", + "type": "felt" + }, + { + "name": "signature_len", + "type": "felt" + }, + { + "name": "signature", + "type": "felt*" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "name": "isValid", + "type": "felt" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "name": "call_array_len", + "type": "felt" + }, + { + "name": "call_array", + "type": "AccountCallArray*" + }, + { + "name": "calldata_len", + "type": "felt" + }, + { + "name": "calldata", + "type": "felt*" + } + ], + "name": "__validate__", + "outputs": [], + "type": "function" + }, + { + "inputs": [ + { + "name": "class_hash", + "type": "felt" + } + ], + "name": "__validate_declare__", + "outputs": [], + "type": "function" + }, + { + "inputs": [ + { + "name": "class_hash", + "type": "felt" + }, + { + "name": "salt", + "type": "felt" + }, + { + "name": "publicKey", + "type": "felt" + } + ], + "name": "__validate_deploy__", + "outputs": [], + "type": "function" + }, + { + "inputs": [ + { + "name": "call_array_len", + "type": "felt" + }, + { + "name": "call_array", + "type": "AccountCallArray*" + }, + { + "name": "calldata_len", + "type": "felt" + }, + { + "name": "calldata", + "type": "felt*" + } + ], + "name": "__execute__", + "outputs": [ + { + "name": "response_len", + "type": "felt" + }, + { + "name": "response", + "type": "felt*" + } + ], + "type": "function" + } + ], + "entry_points_by_type": { + "CONSTRUCTOR": [ + { + "offset": "0x16e", + "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194" + } + ], + "EXTERNAL": [ + { + "offset": "0x1cd", + "selector": "0xbc0eb87884ab91e330445c3584a50d7ddf4b568f02fbeb456a6242cce3f5d9" + }, + { + "offset": "0x2bb", + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" + }, + { + "offset": "0x224", + "selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775" + }, + { + "offset": "0x191", + "selector": "0x1a6c6a0bdec86cc645c91997d8eea83e87148659e3e61122f72361fd5e94079" + }, + { + "offset": "0x1f4", + "selector": "0x213dfe25e2ca309c4d615a09cfc95fdb2fc7dc73fbcad12c450fe93b1f2ff9e" + }, + { + "offset": "0x25f", + "selector": "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3" + }, + { + "offset": "0x1b2", + "selector": "0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd" + }, + { + "offset": "0x285", + "selector": "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895" + } + ], + "L1_HANDLER": [] + }, + "program": { + "debug_info": { + "file_contents": {}, + "instruction_locations": {} + }, + "attributes": [ + { + "accessible_scopes": [ + "openzeppelin.account.library", + "openzeppelin.account.library.Account", + "openzeppelin.account.library.Account.assert_only_self" + ], + "end_pc": 192, + "flow_tracking_data": { + "ap_tracking": { + "group": 16, + "offset": 12 + }, + "reference_ids": {} + }, + "name": "error_message", + "start_pc": 191, + "value": "Account: caller is not this account" + }, + { + "accessible_scopes": [ + "openzeppelin.account.library", + "openzeppelin.account.library.Account", + "openzeppelin.account.library.Account.execute" + ], + "end_pc": 269, + "flow_tracking_data": { + "ap_tracking": { + "group": 21, + "offset": 9 + }, + "reference_ids": {} + }, + "name": "error_message", + "start_pc": 259, + "value": "Account: deprecated tx version" + }, + { + "accessible_scopes": [ + "openzeppelin.account.library", + "openzeppelin.account.library.Account", + "openzeppelin.account.library.Account.execute" + ], + "end_pc": 274, + "flow_tracking_data": { + "ap_tracking": { + "group": 21, + "offset": 49 + }, + "reference_ids": {} + }, + "name": "error_message", + "start_pc": 272, + "value": "Account: reentrant call" + } + ], + "builtins": [ + "pedersen", + "range_check", + "ecdsa", + "bitwise" + ], + "compiler_version": "0.10.2", + "data": [ + "0x40780017fff7fff", + "0x1", + "0x208b7fff7fff7ffe", + "0x20780017fff7ffd", + "0x3", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480080007fff8000", + "0x400080007ffd7fff", + "0x482480017ffd8001", + "0x1", + "0x482480017ffd8001", + "0x1", + "0xa0680017fff7ffe", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffb", + "0x402a7ffc7ffd7fff", + "0x208b7fff7fff7ffe", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x484480017fff8000", + "0x2aaaaaaaaaaaab05555555555555556", + "0x48307fff7ffd8000", + "0x480280027ffb8000", + "0x480280037ffb8000", + "0x484480017fff8000", + "0x4000000000000088000000000000001", + "0x48307fff7ffd8000", + "0xa0680017fff8000", + "0xe", + "0x480680017fff8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x48287ffc80007fff", + "0x40307ffc7ff87fff", + "0x48297ffd80007ffc", + "0x482680017ffd8000", + "0x1", + "0x48507fff7ffe8000", + "0x40507ff97ff57fff", + "0x482680017ffb8000", + "0x4", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0xc", + "0x480680017fff8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x48287ffd80007fff", + "0x48327fff7ffc8000", + "0x40307ffa7ff67fff", + "0x48527ffe7ffc8000", + "0x40507ff97ff57fff", + "0x482680017ffb8000", + "0x4", + "0x208b7fff7fff7ffe", + "0x40317ffd7ff97ffd", + "0x48297ffc80007ffd", + "0x48527fff7ffc8000", + "0x40507ffb7ff77fff", + "0x40780017fff7fff", + "0x2", + "0x482680017ffb8000", + "0x4", + "0x208b7fff7fff7ffe", + "0x48297ffd80007ffc", + "0x20680017fff7fff", + "0x4", + "0x402780017ffc7ffc", + "0x1", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffcc", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x43616c6c436f6e7472616374", + "0x400280007ff97fff", + "0x400380017ff97ffa", + "0x400380027ff97ffb", + "0x400380037ff97ffc", + "0x400380047ff97ffd", + "0x482680017ff98000", + "0x7", + "0x480280057ff98000", + "0x480280067ff98000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x47657443616c6c657241646472657373", + "0x400280007ffd7fff", + "0x482680017ffd8000", + "0x2", + "0x480280017ffd8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x476574436f6e747261637441646472657373", + "0x400280007ffd7fff", + "0x482680017ffd8000", + "0x2", + "0x480280017ffd8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x53746f7261676552656164", + "0x400280007ffc7fff", + "0x400380017ffc7ffd", + "0x482680017ffc8000", + "0x3", + "0x480280027ffc8000", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x53746f726167655772697465", + "0x400280007ffb7fff", + "0x400380017ffb7ffc", + "0x400380027ffb7ffd", + "0x482680017ffb8000", + "0x3", + "0x208b7fff7fff7ffe", + "0x480680017fff8000", + "0x4765745478496e666f", + "0x400280007ffd7fff", + "0x482680017ffd8000", + "0x2", + "0x480280017ffd8000", + "0x208b7fff7fff7ffe", + "0x400380017ff97ffa", + "0x400380007ff97ffb", + "0x482680017ff98000", + "0x2", + "0x208b7fff7fff7ffe", + "0xa0680017fff8000", + "0xc", + "0x40780017fff7fff", + "0x6", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff8c", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffd7fff8000", + "0x480a7ffc7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffb1", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x480680017fff8000", + "0x1379ac0624b939ceb9dede92211d7db5ee174fe28be72245b0a1a2abd81c98f", + "0x208b7fff7fff7ffe", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffffa", + "0x480a7ffb7fff8000", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc6", + "0x48127ffe7fff8000", + "0x48127ff57fff8000", + "0x48127ff57fff8000", + "0x48127ffc7fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffed", + "0x480a7ffa7fff8000", + "0x48127ffe7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc0", + "0x48127ff67fff8000", + "0x48127ff67fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff1", + "0x208b7fff7fff7ffe", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffa4", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff9a", + "0x40127fff7fff7ff9", + "0x48127ffe7fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd5", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffe00365a", + "0x20680017fff7fff", + "0x8", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffff59942a8c", + "0x20680017fff7fff", + "0x8", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd7", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffbf", + "0x208b7fff7fff7ffe", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ffa7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffac", + "0x480a7ff97fff8000", + "0x480a7ffb7fff8000", + "0x48127ffd7fff8000", + "0x480280007ffd8000", + "0x480280017ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff87", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ffd7fff8000", + "0x48127ff37fff8000", + "0x480680017fff8000", + "0x1", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3", + "0x480a7ff57fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff74", + "0x480a7ff97fff8000", + "0x480680017fff8000", + "0x1", + "0x480080007ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff7a", + "0x480680017fff8000", + "0x1", + "0x40127fff7fff7ffe", + "0x40137ffd7fff8000", + "0x48127fdc7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff49", + "0x400680017fff7fff", + "0x0", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffeef", + "0x40137fff7fff8001", + "0x48127ffb7fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffd7fff8000", + "0x480a80017fff8000", + "0x1104800180018000", + "0x35", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffee5", + "0x40137fff7fff8002", + "0x48127ffc7fff8000", + "0x480a7ffa7fff8000", + "0x480a80017fff8000", + "0x480a80027fff8000", + "0x1104800180018000", + "0xa", + "0x48127ffe7fff8000", + "0x480a7ff67fff8000", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a80007fff8000", + "0x48127ffa7fff8000", + "0x480a80027fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3", + "0x20780017fff7ffb", + "0x6", + "0x480a7ffa7fff8000", + "0x480680017fff8000", + "0x0", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480280007ffc8000", + "0x480280017ffc8000", + "0x480280027ffc8000", + "0x480280037ffc8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff11", + "0x40137ffe7fff8000", + "0x40137fff7fff8001", + "0x40137ffd7fff8002", + "0x480a7ffd7fff8000", + "0x480a80017fff8000", + "0x480a80007fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffec2", + "0x480a80027fff8000", + "0x482680017ffb8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x482680017ffc8000", + "0x4", + "0x482a80007ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe4", + "0x48127ffe7fff8000", + "0x482880007ffe8000", + "0x208b7fff7fff7ffe", + "0x20780017fff7ffa", + "0x4", + "0x480a7ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480280007ffb8000", + "0x400280007ffd7fff", + "0x480280017ffb8000", + "0x400280017ffd7fff", + "0x480280037ffb8000", + "0x400280027ffd7fff", + "0x480280027ffb8000", + "0x48327fff7ffc8000", + "0x400280037ffd7fff", + "0x480a7ff97fff8000", + "0x482680017ffa8000", + "0x800000000000011000000000000000000000000000000000000000000000000", + "0x482680017ffb8000", + "0x4", + "0x480a7ffc7fff8000", + "0x482680017ffd8000", + "0x4", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffec", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff48", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x1", + "0x402a7ffd7ffc7fff", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff3", + "0x40780017fff7fff", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480280037ffb8000", + "0x480280047ffb8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff3e", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x4003800080007ffc", + "0x4826800180008000", + "0x1", + "0x480a7ffd7fff8000", + "0x4828800080007ffe", + "0x480a80007fff8000", + "0x208b7fff7fff7ffe", + "0x402b7ffd7ffc7ffd", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280027ffb8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffee", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff1", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ffb7fff8000", + "0x480280037ffb8000", + "0x480280047ffb8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff23", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x4003800080007ffc", + "0x4826800180008000", + "0x1", + "0x480a7ffd7fff8000", + "0x4828800080007ffe", + "0x480a80007fff8000", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x1", + "0x402a7ffd7ffc7fff", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffea", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffee", + "0x48127ff47fff8000", + "0x48127ff47fff8000", + "0x48127ffb7fff8000", + "0x480280037ffb8000", + "0x480280047ffb8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff19", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x1", + "0x402a7ffd7ffc7fff", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffff3", + "0x40780017fff7fff", + "0x1", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x48127ffc7fff8000", + "0x480280037ffb8000", + "0x480280047ffb8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffff04", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x1", + "0x4003800080007ffc", + "0x4826800180008000", + "0x1", + "0x480a7ffd7fff8000", + "0x4828800080007ffe", + "0x480a80007fff8000", + "0x208b7fff7fff7ffe", + "0x480280027ffb8000", + "0x480280017ffd8000", + "0x400080007ffe7fff", + "0x482680017ffd8000", + "0x2", + "0x480280017ffd8000", + "0x48307fff7ffe8000", + "0x402a7ffd7ffc7fff", + "0x480280027ffb8000", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280037ffb8000", + "0x482480017ffc8000", + "0x1", + "0x480280007ffd8000", + "0x480280017ffd8000", + "0x482680017ffd8000", + "0x2", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffdc", + "0x48127ffe7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe3", + "0x48127ff37fff8000", + "0x48127ff37fff8000", + "0x48127ffb7fff8000", + "0x48127ff27fff8000", + "0x480280047ffb8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff67fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe61", + "0x48127ffe7fff8000", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480080057ffb8000", + "0x480080037ffa8000", + "0x480080047ff98000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffecf", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x400080007ffe7fff", + "0x482680017ffd8000", + "0x1", + "0x480280007ffd8000", + "0x484480017fff8000", + "0x4", + "0x48307fff7ffd8000", + "0x480280027ffb8000", + "0x480080007ffe8000", + "0x400080017ffe7fff", + "0x482480017ffd8000", + "0x1", + "0x480080007ffc8000", + "0x48307fff7ffe8000", + "0x402a7ffd7ffc7fff", + "0x480280027ffb8000", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280037ffb8000", + "0x482480017ffc8000", + "0x2", + "0x480280007ffd8000", + "0x482680017ffd8000", + "0x1", + "0x480080007ff38000", + "0x482480017ff28000", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffd3", + "0x40780017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127ffa7fff8000", + "0x480280047ffb8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff97fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe26", + "0x48127ffe7fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480080057ffb8000", + "0x480080037ffa8000", + "0x480080047ff98000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe94", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x1", + "0x402a7ffd7ffc7fff", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280037ffb8000", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe8", + "0x40780017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127ffa7fff8000", + "0x480280047ffb8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff77fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe00", + "0x48127ffe7fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480080057ffb8000", + "0x480080037ffa8000", + "0x480080047ff98000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe6e", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x208b7fff7fff7ffe", + "0x482680017ffd8000", + "0x3", + "0x402a7ffd7ffc7fff", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280037ffb8000", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x480280017ffd8000", + "0x480280027ffd8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffe6", + "0x40780017fff7fff", + "0x1", + "0x48127ffb7fff8000", + "0x48127ffb7fff8000", + "0x48127ffc7fff8000", + "0x48127ffa7fff8000", + "0x480280047ffb8000", + "0x480680017fff8000", + "0x0", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe", + "0x480a7ff57fff8000", + "0x480a7ff67fff8000", + "0x480a7ff77fff8000", + "0x480a7ff87fff8000", + "0x480a7ff97fff8000", + "0x480a7ffa7fff8000", + "0x480a7ffb7fff8000", + "0x480a7ffc7fff8000", + "0x480a7ffd7fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffe5a", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x3", + "0x4003800080007ffb", + "0x400380007ffd7ffb", + "0x402780017ffd8001", + "0x1", + "0x4826800180008000", + "0x1", + "0x40297ffb7fff8002", + "0x4826800180008000", + "0x1", + "0x480a7ffc7fff8000", + "0x480a7ffb7fff8000", + "0x1104800180018000", + "0x800000000000010fffffffffffffffffffffffffffffffffffffffffffffd4f", + "0x480a80017fff8000", + "0x4829800080008002", + "0x480a80007fff8000", + "0x208b7fff7fff7ffe", + "0x40780017fff7fff", + "0x4", + "0x480280027ffb8000", + "0x480280007ffd8000", + "0x400080007ffe7fff", + "0x482680017ffd8000", + "0x1", + "0x480280007ffd8000", + "0x484480017fff8000", + "0x4", + "0x48307fff7ffd8000", + "0x480280027ffb8000", + "0x480080007ffe8000", + "0x400080017ffe7fff", + "0x482480017ffd8000", + "0x1", + "0x480080007ffc8000", + "0x48307fff7ffe8000", + "0x402a7ffd7ffc7fff", + "0x480280027ffb8000", + "0x480280007ffb8000", + "0x480280017ffb8000", + "0x480280037ffb8000", + "0x480280047ffb8000", + "0x482480017ffb8000", + "0x2", + "0x480280007ffd8000", + "0x482680017ffd8000", + "0x1", + "0x480080007ff28000", + "0x482480017ff18000", + "0x1", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc2", + "0x40137ff97fff8000", + "0x40137ffa7fff8001", + "0x40137ffb7fff8002", + "0x40137ffc7fff8003", + "0x48127ffd7fff8000", + "0x1104800180018000", + "0x800000000000010ffffffffffffffffffffffffffffffffffffffffffffffc7", + "0x480a80007fff8000", + "0x480a80017fff8000", + "0x48127ffb7fff8000", + "0x480a80027fff8000", + "0x480a80037fff8000", + "0x48127ff97fff8000", + "0x48127ff97fff8000", + "0x208b7fff7fff7ffe" + ], + "hints": { + "0": [ + { + "accessible_scopes": [ + "starkware.cairo.common.alloc", + "starkware.cairo.common.alloc.alloc" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 0, + "offset": 0 + }, + "reference_ids": {} + } + } + ], + "6": [ + { + "accessible_scopes": [ + "starkware.cairo.common.memcpy", + "starkware.cairo.common.memcpy.memcpy" + ], + "code": "vm_enter_scope({'n': ids.len})", + "flow_tracking_data": { + "ap_tracking": { + "group": 1, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.memcpy.memcpy.len": 0 + } + } + } + ], + "14": [ + { + "accessible_scopes": [ + "starkware.cairo.common.memcpy", + "starkware.cairo.common.memcpy.memcpy" + ], + "code": "n -= 1\nids.continue_copying = 1 if n > 0 else 0", + "flow_tracking_data": { + "ap_tracking": { + "group": 1, + "offset": 5 + }, + "reference_ids": { + "starkware.cairo.common.memcpy.memcpy.continue_copying": 1 + } + } + } + ], + "17": [ + { + "accessible_scopes": [ + "starkware.cairo.common.memcpy", + "starkware.cairo.common.memcpy.memcpy" + ], + "code": "vm_exit_scope()", + "flow_tracking_data": { + "ap_tracking": { + "group": 1, + "offset": 6 + }, + "reference_ids": {} + } + } + ], + "18": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_le_felt" + ], + "code": "import itertools\n\nfrom starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\na = ids.a % PRIME\nb = ids.b % PRIME\nassert a <= b, f'a = {a} is not less than or equal to b = {b}.'\n\n# Find an arc less than PRIME / 3, and another less than PRIME / 2.\nlengths_and_indices = [(a, 0), (b - a, 1), (PRIME - 1 - b, 2)]\nlengths_and_indices.sort()\nassert lengths_and_indices[0][0] <= PRIME // 3 and lengths_and_indices[1][0] <= PRIME // 2\nexcluded = lengths_and_indices[2][1]\n\nmemory[ids.range_check_ptr + 1], memory[ids.range_check_ptr + 0] = (\n divmod(lengths_and_indices[0][0], ids.PRIME_OVER_3_HIGH))\nmemory[ids.range_check_ptr + 3], memory[ids.range_check_ptr + 2] = (\n divmod(lengths_and_indices[1][0], ids.PRIME_OVER_2_HIGH))", + "flow_tracking_data": { + "ap_tracking": { + "group": 2, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.math.assert_le_felt.a": 2, + "starkware.cairo.common.math.assert_le_felt.b": 3, + "starkware.cairo.common.math.assert_le_felt.range_check_ptr": 4 + } + } + } + ], + "28": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_le_felt" + ], + "code": "memory[ap] = 1 if excluded != 0 else 0", + "flow_tracking_data": { + "ap_tracking": { + "group": 2, + "offset": 8 + }, + "reference_ids": {} + } + } + ], + "42": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_le_felt" + ], + "code": "memory[ap] = 1 if excluded != 1 else 0", + "flow_tracking_data": { + "ap_tracking": { + "group": 2, + "offset": 9 + }, + "reference_ids": {} + } + } + ], + "54": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_le_felt" + ], + "code": "assert excluded == 2", + "flow_tracking_data": { + "ap_tracking": { + "group": 2, + "offset": 10 + }, + "reference_ids": {} + } + } + ], + "63": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math", + "starkware.cairo.common.math.assert_lt_felt" + ], + "code": "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.a)\nassert_integer(ids.b)\nassert (ids.a % PRIME) < (ids.b % PRIME), \\\n f'a = {ids.a % PRIME} is not less than b = {ids.b % PRIME}.'", + "flow_tracking_data": { + "ap_tracking": { + "group": 3, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.math.assert_lt_felt.a": 5, + "starkware.cairo.common.math.assert_lt_felt.b": 6 + } + } + } + ], + "81": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.call_contract" + ], + "code": "syscall_handler.call_contract(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 4, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.call_contract.syscall_ptr": 7 + } + } + } + ], + "89": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.get_caller_address" + ], + "code": "syscall_handler.get_caller_address(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 5, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr": 8 + } + } + } + ], + "96": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.get_contract_address" + ], + "code": "syscall_handler.get_contract_address(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 6, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr": 9 + } + } + } + ], + "104": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.storage_read" + ], + "code": "syscall_handler.storage_read(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 7, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.storage_read.syscall_ptr": 10 + } + } + } + ], + "113": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.storage_write" + ], + "code": "syscall_handler.storage_write(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 8, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.storage_write.syscall_ptr": 11 + } + } + } + ], + "119": [ + { + "accessible_scopes": [ + "starkware.starknet.common.syscalls", + "starkware.starknet.common.syscalls.get_tx_info" + ], + "code": "syscall_handler.get_tx_info(segments=segments, syscall_ptr=ids.syscall_ptr)", + "flow_tracking_data": { + "ap_tracking": { + "group": 9, + "offset": 1 + }, + "reference_ids": { + "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": 12 + } + } + } + ], + "123": [ + { + "accessible_scopes": [ + "starkware.cairo.common.signature", + "starkware.cairo.common.signature.verify_ecdsa_signature" + ], + "code": "ecdsa_builtin.add_signature(ids.ecdsa_ptr.address_, (ids.signature_r, ids.signature_s))", + "flow_tracking_data": { + "ap_tracking": { + "group": 10, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr": 15, + "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r": 13, + "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s": 14 + } + } + } + ], + "128": [ + { + "accessible_scopes": [ + "starkware.cairo.common.math_cmp", + "starkware.cairo.common.math_cmp.is_le_felt" + ], + "code": "memory[ap] = 0 if (ids.a % PRIME) <= (ids.b % PRIME) else 1", + "flow_tracking_data": { + "ap_tracking": { + "group": 11, + "offset": 0 + }, + "reference_ids": { + "starkware.cairo.common.math_cmp.is_le_felt.a": 16, + "starkware.cairo.common.math_cmp.is_le_felt.b": 17 + } + } + } + ], + "375": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.constructor" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 30, + "offset": 35 + }, + "reference_ids": {} + } + } + ], + "392": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.getPublicKey_encode_return" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 32, + "offset": 0 + }, + "reference_ids": {} + } + } + ], + "425": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.supportsInterface_encode_return" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 36, + "offset": 0 + }, + "reference_ids": {} + } + } + ], + "470": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.setPublicKey" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 40, + "offset": 50 + }, + "reference_ids": {} + } + } + ], + "491": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.isValidSignature_encode_return" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 42, + "offset": 0 + }, + "reference_ids": {} + } + } + ], + "579": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.__validate__" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 45, + "offset": 77 + }, + "reference_ids": {} + } + } + ], + "617": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.__validate_declare__" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 47, + "offset": 63 + }, + "reference_ids": {} + } + } + ], + "657": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.__validate_deploy__" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 49, + "offset": 65 + }, + "reference_ids": {} + } + } + ], + "680": [ + { + "accessible_scopes": [ + "__main__", + "__main__", + "__wrappers__", + "__wrappers__.__execute___encode_return" + ], + "code": "memory[ap] = segments.add()", + "flow_tracking_data": { + "ap_tracking": { + "group": 52, + "offset": 0 + }, + "reference_ids": {} + } + } + ] + }, + "identifiers": { + "__main__.Account": { + "destination": "openzeppelin.account.library.Account", + "type": "alias" + }, + "__main__.AccountCallArray": { + "destination": "openzeppelin.account.library.AccountCallArray", + "type": "alias" + }, + "__main__.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "__main__.HashBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "type": "alias" + }, + "__main__.SignatureBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", + "type": "alias" + }, + "__main__.__execute__": { + "decorators": [ + "external" + ], + "pc": 668, + "type": "function" + }, + "__main__.__execute__.Args": { + "full_name": "__main__.__execute__.Args", + "members": { + "call_array": { + "cairo_type": "openzeppelin.account.library.AccountCallArray*", + "offset": 1 + }, + "call_array_len": { + "cairo_type": "felt", + "offset": 0 + }, + "calldata": { + "cairo_type": "felt*", + "offset": 3 + }, + "calldata_len": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.__execute__.ImplicitArgs": { + "full_name": "__main__.__execute__.ImplicitArgs", + "members": { + "bitwise_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin*", + "offset": 3 + }, + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 4 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 5, + "type": "struct" + }, + "__main__.__execute__.Return": { + "cairo_type": "(response_len: felt, response: felt*)", + "type": "type_definition" + }, + "__main__.__execute__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.__validate__": { + "decorators": [ + "external" + ], + "pc": 531, + "type": "function" + }, + "__main__.__validate__.Args": { + "full_name": "__main__.__validate__.Args", + "members": { + "call_array": { + "cairo_type": "openzeppelin.account.library.AccountCallArray*", + "offset": 1 + }, + "call_array_len": { + "cairo_type": "felt", + "offset": 0 + }, + "calldata": { + "cairo_type": "felt*", + "offset": 3 + }, + "calldata_len": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.__validate__.ImplicitArgs": { + "full_name": "__main__.__validate__.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 3 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.__validate__.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "__main__.__validate__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.__validate_declare__": { + "decorators": [ + "external" + ], + "pc": 590, + "type": "function" + }, + "__main__.__validate_declare__.Args": { + "full_name": "__main__.__validate_declare__.Args", + "members": { + "class_hash": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "__main__.__validate_declare__.ImplicitArgs": { + "full_name": "__main__.__validate_declare__.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 3 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.__validate_declare__.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "__main__.__validate_declare__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.__validate_deploy__": { + "decorators": [ + "external" + ], + "pc": 628, + "type": "function" + }, + "__main__.__validate_deploy__.Args": { + "full_name": "__main__.__validate_deploy__.Args", + "members": { + "class_hash": { + "cairo_type": "felt", + "offset": 0 + }, + "publicKey": { + "cairo_type": "felt", + "offset": 2 + }, + "salt": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.__validate_deploy__.ImplicitArgs": { + "full_name": "__main__.__validate_deploy__.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 3 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.__validate_deploy__.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "__main__.__validate_deploy__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.constructor": { + "decorators": [ + "constructor" + ], + "pc": 359, + "type": "function" + }, + "__main__.constructor.Args": { + "full_name": "__main__.constructor.Args", + "members": { + "publicKey": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "__main__.constructor.ImplicitArgs": { + "full_name": "__main__.constructor.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.constructor.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "__main__.constructor.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.getPublicKey": { + "decorators": [ + "view" + ], + "pc": 386, + "type": "function" + }, + "__main__.getPublicKey.Args": { + "full_name": "__main__.getPublicKey.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__main__.getPublicKey.ImplicitArgs": { + "full_name": "__main__.getPublicKey.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.getPublicKey.Return": { + "cairo_type": "(publicKey: felt)", + "type": "type_definition" + }, + "__main__.getPublicKey.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.get_tx_info": { + "destination": "starkware.starknet.common.syscalls.get_tx_info", + "type": "alias" + }, + "__main__.isValidSignature": { + "decorators": [ + "view" + ], + "pc": 481, + "type": "function" + }, + "__main__.isValidSignature.Args": { + "full_name": "__main__.isValidSignature.Args", + "members": { + "hash": { + "cairo_type": "felt", + "offset": 0 + }, + "signature": { + "cairo_type": "felt*", + "offset": 2 + }, + "signature_len": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.isValidSignature.ImplicitArgs": { + "full_name": "__main__.isValidSignature.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 3 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "__main__.isValidSignature.Return": { + "cairo_type": "(isValid: felt)", + "type": "type_definition" + }, + "__main__.isValidSignature.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.setPublicKey": { + "decorators": [ + "external" + ], + "pc": 454, + "type": "function" + }, + "__main__.setPublicKey.Args": { + "full_name": "__main__.setPublicKey.Args", + "members": { + "newPublicKey": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "__main__.setPublicKey.ImplicitArgs": { + "full_name": "__main__.setPublicKey.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.setPublicKey.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "__main__.setPublicKey.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__main__.supportsInterface": { + "decorators": [ + "view" + ], + "pc": 418, + "type": "function" + }, + "__main__.supportsInterface.Args": { + "full_name": "__main__.supportsInterface.Args", + "members": { + "interfaceId": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "__main__.supportsInterface.ImplicitArgs": { + "full_name": "__main__.supportsInterface.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "__main__.supportsInterface.Return": { + "cairo_type": "(success: felt)", + "type": "type_definition" + }, + "__main__.supportsInterface.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.__execute__": { + "decorators": [ + "external" + ], + "pc": 699, + "type": "function" + }, + "__wrappers__.__execute__.Args": { + "full_name": "__wrappers__.__execute__.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__execute__.ImplicitArgs": { + "full_name": "__wrappers__.__execute__.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__execute__.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: starkware.cairo.common.cairo_builtins.BitwiseBuiltin*, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.__execute__.SIZEOF_LOCALS": { + "type": "const", + "value": 4 + }, + "__wrappers__.__execute__.__wrapped_func": { + "destination": "__main__.__execute__", + "type": "alias" + }, + "__wrappers__.__execute___encode_return": { + "decorators": [], + "pc": 680, + "type": "function" + }, + "__wrappers__.__execute___encode_return.Args": { + "full_name": "__wrappers__.__execute___encode_return.Args", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "ret_value": { + "cairo_type": "(response_len: felt, response: felt*)", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "__wrappers__.__execute___encode_return.ImplicitArgs": { + "full_name": "__wrappers__.__execute___encode_return.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__execute___encode_return.Return": { + "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", + "type": "type_definition" + }, + "__wrappers__.__execute___encode_return.SIZEOF_LOCALS": { + "type": "const", + "value": 3 + }, + "__wrappers__.__execute___encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.__validate__": { + "decorators": [ + "external" + ], + "pc": 548, + "type": "function" + }, + "__wrappers__.__validate__.Args": { + "full_name": "__wrappers__.__validate__.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate__.ImplicitArgs": { + "full_name": "__wrappers__.__validate__.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate__.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.__validate__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.__validate__.__wrapped_func": { + "destination": "__main__.__validate__", + "type": "alias" + }, + "__wrappers__.__validate___encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.__validate_declare__": { + "decorators": [ + "external" + ], + "pc": 607, + "type": "function" + }, + "__wrappers__.__validate_declare__.Args": { + "full_name": "__wrappers__.__validate_declare__.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate_declare__.ImplicitArgs": { + "full_name": "__wrappers__.__validate_declare__.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate_declare__.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.__validate_declare__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.__validate_declare__.__wrapped_func": { + "destination": "__main__.__validate_declare__", + "type": "alias" + }, + "__wrappers__.__validate_declare___encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.__validate_deploy__": { + "decorators": [ + "external" + ], + "pc": 645, + "type": "function" + }, + "__wrappers__.__validate_deploy__.Args": { + "full_name": "__wrappers__.__validate_deploy__.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate_deploy__.ImplicitArgs": { + "full_name": "__wrappers__.__validate_deploy__.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.__validate_deploy__.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.__validate_deploy__.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.__validate_deploy__.__wrapped_func": { + "destination": "__main__.__validate_deploy__", + "type": "alias" + }, + "__wrappers__.__validate_deploy___encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.constructor": { + "decorators": [ + "constructor" + ], + "pc": 366, + "type": "function" + }, + "__wrappers__.constructor.Args": { + "full_name": "__wrappers__.constructor.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.constructor.ImplicitArgs": { + "full_name": "__wrappers__.constructor.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.constructor.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.constructor.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.constructor.__wrapped_func": { + "destination": "__main__.constructor", + "type": "alias" + }, + "__wrappers__.constructor_encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.getPublicKey": { + "decorators": [ + "view" + ], + "pc": 401, + "type": "function" + }, + "__wrappers__.getPublicKey.Args": { + "full_name": "__wrappers__.getPublicKey.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.getPublicKey.ImplicitArgs": { + "full_name": "__wrappers__.getPublicKey.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.getPublicKey.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.getPublicKey.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.getPublicKey.__wrapped_func": { + "destination": "__main__.getPublicKey", + "type": "alias" + }, + "__wrappers__.getPublicKey_encode_return": { + "decorators": [], + "pc": 392, + "type": "function" + }, + "__wrappers__.getPublicKey_encode_return.Args": { + "full_name": "__wrappers__.getPublicKey_encode_return.Args", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 1 + }, + "ret_value": { + "cairo_type": "(publicKey: felt)", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "__wrappers__.getPublicKey_encode_return.ImplicitArgs": { + "full_name": "__wrappers__.getPublicKey_encode_return.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.getPublicKey_encode_return.Return": { + "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", + "type": "type_definition" + }, + "__wrappers__.getPublicKey_encode_return.SIZEOF_LOCALS": { + "type": "const", + "value": 1 + }, + "__wrappers__.getPublicKey_encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.isValidSignature": { + "decorators": [ + "view" + ], + "pc": 500, + "type": "function" + }, + "__wrappers__.isValidSignature.Args": { + "full_name": "__wrappers__.isValidSignature.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.isValidSignature.ImplicitArgs": { + "full_name": "__wrappers__.isValidSignature.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.isValidSignature.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: starkware.cairo.common.cairo_builtins.SignatureBuiltin*, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.isValidSignature.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.isValidSignature.__wrapped_func": { + "destination": "__main__.isValidSignature", + "type": "alias" + }, + "__wrappers__.isValidSignature_encode_return": { + "decorators": [], + "pc": 491, + "type": "function" + }, + "__wrappers__.isValidSignature_encode_return.Args": { + "full_name": "__wrappers__.isValidSignature_encode_return.Args", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 1 + }, + "ret_value": { + "cairo_type": "(isValid: felt)", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "__wrappers__.isValidSignature_encode_return.ImplicitArgs": { + "full_name": "__wrappers__.isValidSignature_encode_return.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.isValidSignature_encode_return.Return": { + "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", + "type": "type_definition" + }, + "__wrappers__.isValidSignature_encode_return.SIZEOF_LOCALS": { + "type": "const", + "value": 1 + }, + "__wrappers__.isValidSignature_encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.setPublicKey": { + "decorators": [ + "external" + ], + "pc": 461, + "type": "function" + }, + "__wrappers__.setPublicKey.Args": { + "full_name": "__wrappers__.setPublicKey.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.setPublicKey.ImplicitArgs": { + "full_name": "__wrappers__.setPublicKey.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.setPublicKey.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.setPublicKey.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.setPublicKey.__wrapped_func": { + "destination": "__main__.setPublicKey", + "type": "alias" + }, + "__wrappers__.setPublicKey_encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "__wrappers__.supportsInterface": { + "decorators": [ + "view" + ], + "pc": 434, + "type": "function" + }, + "__wrappers__.supportsInterface.Args": { + "full_name": "__wrappers__.supportsInterface.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.supportsInterface.ImplicitArgs": { + "full_name": "__wrappers__.supportsInterface.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.supportsInterface.Return": { + "cairo_type": "(syscall_ptr: felt*, pedersen_ptr: starkware.cairo.common.cairo_builtins.HashBuiltin*, range_check_ptr: felt, ecdsa_ptr: felt, bitwise_ptr: felt, size: felt, retdata: felt*)", + "type": "type_definition" + }, + "__wrappers__.supportsInterface.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "__wrappers__.supportsInterface.__wrapped_func": { + "destination": "__main__.supportsInterface", + "type": "alias" + }, + "__wrappers__.supportsInterface_encode_return": { + "decorators": [], + "pc": 425, + "type": "function" + }, + "__wrappers__.supportsInterface_encode_return.Args": { + "full_name": "__wrappers__.supportsInterface_encode_return.Args", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 1 + }, + "ret_value": { + "cairo_type": "(success: felt)", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "__wrappers__.supportsInterface_encode_return.ImplicitArgs": { + "full_name": "__wrappers__.supportsInterface_encode_return.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "__wrappers__.supportsInterface_encode_return.Return": { + "cairo_type": "(range_check_ptr: felt, data_len: felt, data: felt*)", + "type": "type_definition" + }, + "__wrappers__.supportsInterface_encode_return.SIZEOF_LOCALS": { + "type": "const", + "value": 1 + }, + "__wrappers__.supportsInterface_encode_return.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "openzeppelin.account.library.Account": { + "type": "namespace" + }, + "openzeppelin.account.library.Account.Args": { + "full_name": "openzeppelin.account.library.Account.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account._execute_list": { + "decorators": [], + "pc": 301, + "type": "function" + }, + "openzeppelin.account.library.Account._execute_list.Args": { + "full_name": "openzeppelin.account.library.Account._execute_list.Args", + "members": { + "calls": { + "cairo_type": "openzeppelin.account.library.Call*", + "offset": 1 + }, + "calls_len": { + "cairo_type": "felt", + "offset": 0 + }, + "response": { + "cairo_type": "felt*", + "offset": 2 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account._execute_list.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account._execute_list.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account._execute_list.Return": { + "cairo_type": "(response_len: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account._execute_list.SIZEOF_LOCALS": { + "type": "const", + "value": 3 + }, + "openzeppelin.account.library.Account._from_call_array_to_call": { + "decorators": [], + "pc": 335, + "type": "function" + }, + "openzeppelin.account.library.Account._from_call_array_to_call.Args": { + "full_name": "openzeppelin.account.library.Account._from_call_array_to_call.Args", + "members": { + "call_array": { + "cairo_type": "openzeppelin.account.library.AccountCallArray*", + "offset": 1 + }, + "call_array_len": { + "cairo_type": "felt", + "offset": 0 + }, + "calldata": { + "cairo_type": "felt*", + "offset": 2 + }, + "calls": { + "cairo_type": "openzeppelin.account.library.Call*", + "offset": 3 + } + }, + "size": 4, + "type": "struct" + }, + "openzeppelin.account.library.Account._from_call_array_to_call.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account._from_call_array_to_call.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account._from_call_array_to_call.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account._from_call_array_to_call.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.assert_only_self": { + "decorators": [], + "pc": 185, + "type": "function" + }, + "openzeppelin.account.library.Account.assert_only_self.Args": { + "full_name": "openzeppelin.account.library.Account.assert_only_self.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account.assert_only_self.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.assert_only_self.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account.assert_only_self.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.assert_only_self.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.execute": { + "decorators": [], + "pc": 254, + "type": "function" + }, + "openzeppelin.account.library.Account.execute.Args": { + "full_name": "openzeppelin.account.library.Account.execute.Args", + "members": { + "call_array": { + "cairo_type": "openzeppelin.account.library.AccountCallArray*", + "offset": 1 + }, + "call_array_len": { + "cairo_type": "felt", + "offset": 0 + }, + "calldata": { + "cairo_type": "felt*", + "offset": 3 + }, + "calldata_len": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 4, + "type": "struct" + }, + "openzeppelin.account.library.Account.execute.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.execute.ImplicitArgs", + "members": { + "bitwise_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin*", + "offset": 3 + }, + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 4 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 5, + "type": "struct" + }, + "openzeppelin.account.library.Account.execute.Return": { + "cairo_type": "(response_len: felt, response: felt*)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.execute.SIZEOF_LOCALS": { + "type": "const", + "value": 3 + }, + "openzeppelin.account.library.Account.get_public_key": { + "decorators": [], + "pc": 194, + "type": "function" + }, + "openzeppelin.account.library.Account.get_public_key.Args": { + "full_name": "openzeppelin.account.library.Account.get_public_key.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account.get_public_key.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.get_public_key.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account.get_public_key.Return": { + "cairo_type": "(public_key: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.get_public_key.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.initializer": { + "decorators": [], + "pc": 178, + "type": "function" + }, + "openzeppelin.account.library.Account.initializer.Args": { + "full_name": "openzeppelin.account.library.Account.initializer.Args", + "members": { + "_public_key": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account.initializer.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.initializer.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account.initializer.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.initializer.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.is_valid_signature": { + "decorators": [], + "pc": 235, + "type": "function" + }, + "openzeppelin.account.library.Account.is_valid_signature.Args": { + "full_name": "openzeppelin.account.library.Account.is_valid_signature.Args", + "members": { + "hash": { + "cairo_type": "felt", + "offset": 0 + }, + "signature": { + "cairo_type": "felt*", + "offset": 2 + }, + "signature_len": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account.is_valid_signature.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.is_valid_signature.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 2 + }, + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 3 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "openzeppelin.account.library.Account.is_valid_signature.Return": { + "cairo_type": "(is_valid: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.is_valid_signature.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.set_public_key": { + "decorators": [], + "pc": 226, + "type": "function" + }, + "openzeppelin.account.library.Account.set_public_key.Args": { + "full_name": "openzeppelin.account.library.Account.set_public_key.Args", + "members": { + "new_public_key": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account.set_public_key.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.set_public_key.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account.set_public_key.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.set_public_key.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account.supports_interface": { + "decorators": [], + "pc": 200, + "type": "function" + }, + "openzeppelin.account.library.Account.supports_interface.Args": { + "full_name": "openzeppelin.account.library.Account.supports_interface.Args", + "members": { + "interface_id": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account.supports_interface.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account.supports_interface.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account.supports_interface.Return": { + "cairo_type": "(success: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account.supports_interface.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.AccountCallArray": { + "full_name": "openzeppelin.account.library.AccountCallArray", + "members": { + "data_len": { + "cairo_type": "felt", + "offset": 3 + }, + "data_offset": { + "cairo_type": "felt", + "offset": 2 + }, + "selector": { + "cairo_type": "felt", + "offset": 1 + }, + "to": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key": { + "type": "namespace" + }, + "openzeppelin.account.library.Account_public_key.Args": { + "full_name": "openzeppelin.account.library.Account_public_key.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.HashBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "type": "alias" + }, + "openzeppelin.account.library.Account_public_key.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account_public_key.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account_public_key.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account_public_key.addr": { + "decorators": [], + "pc": 148, + "type": "function" + }, + "openzeppelin.account.library.Account_public_key.addr.Args": { + "full_name": "openzeppelin.account.library.Account_public_key.addr.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.addr.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account_public_key.addr.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 0 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.addr.Return": { + "cairo_type": "(res: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account_public_key.addr.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account_public_key.hash2": { + "destination": "starkware.cairo.common.hash.hash2", + "type": "alias" + }, + "openzeppelin.account.library.Account_public_key.normalize_address": { + "destination": "starkware.starknet.common.storage.normalize_address", + "type": "alias" + }, + "openzeppelin.account.library.Account_public_key.read": { + "decorators": [], + "pc": 153, + "type": "function" + }, + "openzeppelin.account.library.Account_public_key.read.Args": { + "full_name": "openzeppelin.account.library.Account_public_key.read.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.read.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account_public_key.read.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.read.Return": { + "cairo_type": "(public_key: felt)", + "type": "type_definition" + }, + "openzeppelin.account.library.Account_public_key.read.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.Account_public_key.storage_read": { + "destination": "starkware.starknet.common.syscalls.storage_read", + "type": "alias" + }, + "openzeppelin.account.library.Account_public_key.storage_write": { + "destination": "starkware.starknet.common.syscalls.storage_write", + "type": "alias" + }, + "openzeppelin.account.library.Account_public_key.write": { + "decorators": [], + "pc": 166, + "type": "function" + }, + "openzeppelin.account.library.Account_public_key.write.Args": { + "full_name": "openzeppelin.account.library.Account_public_key.write.Args", + "members": { + "value": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.write.ImplicitArgs": { + "full_name": "openzeppelin.account.library.Account_public_key.write.ImplicitArgs", + "members": { + "pedersen_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.HashBuiltin*", + "offset": 1 + }, + "range_check_ptr": { + "cairo_type": "felt", + "offset": 2 + }, + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "openzeppelin.account.library.Account_public_key.write.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "openzeppelin.account.library.Account_public_key.write.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "openzeppelin.account.library.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "openzeppelin.account.library.Call": { + "full_name": "openzeppelin.account.library.Call", + "members": { + "calldata": { + "cairo_type": "felt*", + "offset": 3 + }, + "calldata_len": { + "cairo_type": "felt", + "offset": 2 + }, + "selector": { + "cairo_type": "felt", + "offset": 1 + }, + "to": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 4, + "type": "struct" + }, + "openzeppelin.account.library.FALSE": { + "destination": "starkware.cairo.common.bool.FALSE", + "type": "alias" + }, + "openzeppelin.account.library.HashBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "type": "alias" + }, + "openzeppelin.account.library.IACCOUNT_ID": { + "destination": "openzeppelin.utils.constants.library.IACCOUNT_ID", + "type": "alias" + }, + "openzeppelin.account.library.IERC165_ID": { + "destination": "openzeppelin.utils.constants.library.IERC165_ID", + "type": "alias" + }, + "openzeppelin.account.library.SignatureBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", + "type": "alias" + }, + "openzeppelin.account.library.TRANSACTION_VERSION": { + "destination": "openzeppelin.utils.constants.library.TRANSACTION_VERSION", + "type": "alias" + }, + "openzeppelin.account.library.TRUE": { + "destination": "starkware.cairo.common.bool.TRUE", + "type": "alias" + }, + "openzeppelin.account.library.Uint256": { + "destination": "starkware.cairo.common.uint256.Uint256", + "type": "alias" + }, + "openzeppelin.account.library.alloc": { + "destination": "starkware.cairo.common.alloc.alloc", + "type": "alias" + }, + "openzeppelin.account.library.call_contract": { + "destination": "starkware.starknet.common.syscalls.call_contract", + "type": "alias" + }, + "openzeppelin.account.library.get_caller_address": { + "destination": "starkware.starknet.common.syscalls.get_caller_address", + "type": "alias" + }, + "openzeppelin.account.library.get_contract_address": { + "destination": "starkware.starknet.common.syscalls.get_contract_address", + "type": "alias" + }, + "openzeppelin.account.library.get_fp_and_pc": { + "destination": "starkware.cairo.common.registers.get_fp_and_pc", + "type": "alias" + }, + "openzeppelin.account.library.get_tx_info": { + "destination": "starkware.starknet.common.syscalls.get_tx_info", + "type": "alias" + }, + "openzeppelin.account.library.is_le_felt": { + "destination": "starkware.cairo.common.math_cmp.is_le_felt", + "type": "alias" + }, + "openzeppelin.account.library.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "openzeppelin.account.library.split_felt": { + "destination": "starkware.cairo.common.math.split_felt", + "type": "alias" + }, + "openzeppelin.account.library.verify_ecdsa_signature": { + "destination": "starkware.cairo.common.signature.verify_ecdsa_signature", + "type": "alias" + }, + "openzeppelin.account.library.verify_eth_signature_uint256": { + "destination": "starkware.cairo.common.cairo_secp.signature.verify_eth_signature_uint256", + "type": "alias" + }, + "openzeppelin.utils.constants.library.DEFAULT_ADMIN_ROLE": { + "type": "const", + "value": 0 + }, + "openzeppelin.utils.constants.library.IACCESSCONTROL_ID": { + "type": "const", + "value": 2036718347 + }, + "openzeppelin.utils.constants.library.IACCOUNT_ID": { + "type": "const", + "value": 2792084853 + }, + "openzeppelin.utils.constants.library.IERC165_ID": { + "type": "const", + "value": 33540519 + }, + "openzeppelin.utils.constants.library.IERC721_ENUMERABLE_ID": { + "type": "const", + "value": 2014223715 + }, + "openzeppelin.utils.constants.library.IERC721_ID": { + "type": "const", + "value": 2158778573 + }, + "openzeppelin.utils.constants.library.IERC721_METADATA_ID": { + "type": "const", + "value": 1532892063 + }, + "openzeppelin.utils.constants.library.IERC721_RECEIVER_ID": { + "type": "const", + "value": 353073666 + }, + "openzeppelin.utils.constants.library.INVALID_ID": { + "type": "const", + "value": 4294967295 + }, + "openzeppelin.utils.constants.library.TRANSACTION_VERSION": { + "type": "const", + "value": 1 + }, + "openzeppelin.utils.constants.library.UINT8_MAX": { + "type": "const", + "value": 255 + }, + "starkware.cairo.common.alloc.alloc": { + "decorators": [], + "pc": 0, + "type": "function" + }, + "starkware.cairo.common.alloc.alloc.Args": { + "full_name": "starkware.cairo.common.alloc.alloc.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.alloc.alloc.ImplicitArgs": { + "full_name": "starkware.cairo.common.alloc.alloc.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.alloc.alloc.Return": { + "cairo_type": "(ptr: felt*)", + "type": "type_definition" + }, + "starkware.cairo.common.alloc.alloc.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.bitwise.ALL_ONES": { + "type": "const", + "value": -106710729501573572985208420194530329073740042555888586719234 + }, + "starkware.cairo.common.bitwise.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "starkware.cairo.common.bool.FALSE": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.bool.TRUE": { + "type": "const", + "value": 1 + }, + "starkware.cairo.common.cairo_builtins.BitwiseBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "members": { + "x": { + "cairo_type": "felt", + "offset": 0 + }, + "x_and_y": { + "cairo_type": "felt", + "offset": 2 + }, + "x_or_y": { + "cairo_type": "felt", + "offset": 4 + }, + "x_xor_y": { + "cairo_type": "felt", + "offset": 3 + }, + "y": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 5, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.EcOpBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", + "members": { + "m": { + "cairo_type": "felt", + "offset": 4 + }, + "p": { + "cairo_type": "starkware.cairo.common.ec_point.EcPoint", + "offset": 0 + }, + "q": { + "cairo_type": "starkware.cairo.common.ec_point.EcPoint", + "offset": 2 + }, + "r": { + "cairo_type": "starkware.cairo.common.ec_point.EcPoint", + "offset": 5 + } + }, + "size": 7, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.EcPoint": { + "destination": "starkware.cairo.common.ec_point.EcPoint", + "type": "alias" + }, + "starkware.cairo.common.cairo_builtins.HashBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "members": { + "result": { + "cairo_type": "felt", + "offset": 2 + }, + "x": { + "cairo_type": "felt", + "offset": 0 + }, + "y": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.KeccakBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.KeccakBuiltin", + "members": { + "input": { + "cairo_type": "starkware.cairo.common.keccak_state.KeccakBuiltinState", + "offset": 0 + }, + "output": { + "cairo_type": "starkware.cairo.common.keccak_state.KeccakBuiltinState", + "offset": 8 + } + }, + "size": 16, + "type": "struct" + }, + "starkware.cairo.common.cairo_builtins.KeccakBuiltinState": { + "destination": "starkware.cairo.common.keccak_state.KeccakBuiltinState", + "type": "alias" + }, + "starkware.cairo.common.cairo_builtins.SignatureBuiltin": { + "full_name": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", + "members": { + "message": { + "cairo_type": "felt", + "offset": 1 + }, + "pub_key": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.cairo_keccak.keccak.BLOCK_SIZE": { + "destination": "starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.BYTES_IN_WORD": { + "type": "const", + "value": 8 + }, + "starkware.cairo.common.cairo_keccak.keccak.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.KECCAK_CAPACITY_IN_WORDS": { + "type": "const", + "value": 8 + }, + "starkware.cairo.common.cairo_keccak.keccak.KECCAK_FULL_RATE_IN_BYTES": { + "type": "const", + "value": 136 + }, + "starkware.cairo.common.cairo_keccak.keccak.KECCAK_FULL_RATE_IN_WORDS": { + "type": "const", + "value": 17 + }, + "starkware.cairo.common.cairo_keccak.keccak.KECCAK_STATE_SIZE_FELTS": { + "type": "const", + "value": 25 + }, + "starkware.cairo.common.cairo_keccak.keccak.Uint256": { + "destination": "starkware.cairo.common.uint256.Uint256", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.alloc": { + "destination": "starkware.cairo.common.alloc.alloc", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.assert_lt": { + "destination": "starkware.cairo.common.math.assert_lt", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.assert_nn": { + "destination": "starkware.cairo.common.math.assert_nn", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.assert_nn_le": { + "destination": "starkware.cairo.common.math.assert_nn_le", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.assert_not_zero": { + "destination": "starkware.cairo.common.math.assert_not_zero", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.bitwise_and": { + "destination": "starkware.cairo.common.bitwise.bitwise_and", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.bitwise_or": { + "destination": "starkware.cairo.common.bitwise.bitwise_or", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.bitwise_xor": { + "destination": "starkware.cairo.common.bitwise.bitwise_xor", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.memcpy": { + "destination": "starkware.cairo.common.memcpy.memcpy", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.memset": { + "destination": "starkware.cairo.common.memset.memset", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.packed_keccak_func": { + "destination": "starkware.cairo.common.cairo_keccak.packed_keccak.packed_keccak_func", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.pow": { + "destination": "starkware.cairo.common.pow.pow", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.split_felt": { + "destination": "starkware.cairo.common.math.split_felt", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.uint256_reverse_endian": { + "destination": "starkware.cairo.common.uint256.uint256_reverse_endian", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem": { + "destination": "starkware.cairo.common.math.unsigned_div_rem", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.ALL_ONES": { + "type": "const", + "value": -106710729501573572985208420194530329073740042555888586719234 + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE": { + "type": "const", + "value": 3 + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.SHIFTS": { + "type": "const", + "value": 340282366920938463481821351505477763073 + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.alloc": { + "destination": "starkware.cairo.common.alloc.alloc", + "type": "alias" + }, + "starkware.cairo.common.cairo_keccak.packed_keccak.get_fp_and_pc": { + "destination": "starkware.cairo.common.registers.get_fp_and_pc", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.BASE": { + "destination": "starkware.cairo.common.cairo_secp.constants.BASE", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.BigInt3": { + "full_name": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "members": { + "d0": { + "cairo_type": "felt", + "offset": 0 + }, + "d1": { + "cairo_type": "felt", + "offset": 1 + }, + "d2": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.cairo_secp.bigint.RC_BOUND": { + "destination": "starkware.cairo.common.math_cmp.RC_BOUND", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.Uint256": { + "destination": "starkware.cairo.common.uint256.Uint256", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3": { + "full_name": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", + "members": { + "d0": { + "cairo_type": "felt", + "offset": 0 + }, + "d1": { + "cairo_type": "felt", + "offset": 1 + }, + "d2": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt5": { + "full_name": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt5", + "members": { + "d0": { + "cairo_type": "felt", + "offset": 0 + }, + "d1": { + "cairo_type": "felt", + "offset": 1 + }, + "d2": { + "cairo_type": "felt", + "offset": 2 + }, + "d3": { + "cairo_type": "felt", + "offset": 3 + }, + "d4": { + "cairo_type": "felt", + "offset": 4 + } + }, + "size": 5, + "type": "struct" + }, + "starkware.cairo.common.cairo_secp.bigint.assert_nn": { + "destination": "starkware.cairo.common.math.assert_nn", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.assert_nn_le": { + "destination": "starkware.cairo.common.math.assert_nn_le", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.bigint.unsigned_div_rem": { + "destination": "starkware.cairo.common.math.unsigned_div_rem", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.constants.BASE": { + "type": "const", + "value": 77371252455336267181195264 + }, + "starkware.cairo.common.cairo_secp.constants.BETA": { + "type": "const", + "value": 7 + }, + "starkware.cairo.common.cairo_secp.constants.N0": { + "type": "const", + "value": 10428087374290690730508609 + }, + "starkware.cairo.common.cairo_secp.constants.N1": { + "type": "const", + "value": 77371252455330678278691517 + }, + "starkware.cairo.common.cairo_secp.constants.N2": { + "type": "const", + "value": 19342813113834066795298815 + }, + "starkware.cairo.common.cairo_secp.constants.P0": { + "type": "const", + "value": 77371252455336262886226991 + }, + "starkware.cairo.common.cairo_secp.constants.P1": { + "type": "const", + "value": 77371252455336267181195263 + }, + "starkware.cairo.common.cairo_secp.constants.P2": { + "type": "const", + "value": 19342813113834066795298815 + }, + "starkware.cairo.common.cairo_secp.constants.SECP_REM": { + "type": "const", + "value": 4294968273 + }, + "starkware.cairo.common.cairo_secp.ec.BigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.EcPoint": { + "full_name": "starkware.cairo.common.cairo_secp.ec.EcPoint", + "members": { + "x": { + "cairo_type": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "offset": 0 + }, + "y": { + "cairo_type": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "offset": 3 + } + }, + "size": 6, + "type": "struct" + }, + "starkware.cairo.common.cairo_secp.ec.UnreducedBigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.is_zero": { + "destination": "starkware.cairo.common.cairo_secp.field.is_zero", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.nondet_bigint3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.unreduced_mul": { + "destination": "starkware.cairo.common.cairo_secp.field.unreduced_mul", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.unreduced_sqr": { + "destination": "starkware.cairo.common.cairo_secp.field.unreduced_sqr", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.ec.verify_zero": { + "destination": "starkware.cairo.common.cairo_secp.field.verify_zero", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.BASE": { + "destination": "starkware.cairo.common.cairo_secp.constants.BASE", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.BigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.P0": { + "destination": "starkware.cairo.common.cairo_secp.constants.P0", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.P1": { + "destination": "starkware.cairo.common.cairo_secp.constants.P1", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.P2": { + "destination": "starkware.cairo.common.cairo_secp.constants.P2", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.SECP_REM": { + "destination": "starkware.cairo.common.cairo_secp.constants.SECP_REM", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.UnreducedBigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.assert_nn_le": { + "destination": "starkware.cairo.common.math.assert_nn_le", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.field.nondet_bigint3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.BASE": { + "destination": "starkware.cairo.common.cairo_secp.bigint.BASE", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.BETA": { + "destination": "starkware.cairo.common.cairo_secp.constants.BETA", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.BigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.BigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.EcPoint": { + "destination": "starkware.cairo.common.cairo_secp.ec.EcPoint", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.N0": { + "destination": "starkware.cairo.common.cairo_secp.constants.N0", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.N1": { + "destination": "starkware.cairo.common.cairo_secp.constants.N1", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.N2": { + "destination": "starkware.cairo.common.cairo_secp.constants.N2", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.RC_BOUND": { + "destination": "starkware.cairo.common.math_cmp.RC_BOUND", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.Uint256": { + "destination": "starkware.cairo.common.uint256.Uint256", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.UnreducedBigInt3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.UnreducedBigInt3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.alloc": { + "destination": "starkware.cairo.common.alloc.alloc", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.assert_nn": { + "destination": "starkware.cairo.common.math.assert_nn", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.assert_nn_le": { + "destination": "starkware.cairo.common.math.assert_nn_le", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.assert_not_zero": { + "destination": "starkware.cairo.common.math.assert_not_zero", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.bigint_mul": { + "destination": "starkware.cairo.common.cairo_secp.bigint.bigint_mul", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.bigint_to_uint256": { + "destination": "starkware.cairo.common.cairo_secp.bigint.bigint_to_uint256", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.ec_add": { + "destination": "starkware.cairo.common.cairo_secp.ec.ec_add", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.ec_mul": { + "destination": "starkware.cairo.common.cairo_secp.ec.ec_mul", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.ec_negate": { + "destination": "starkware.cairo.common.cairo_secp.ec.ec_negate", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.finalize_keccak": { + "destination": "starkware.cairo.common.cairo_keccak.keccak.finalize_keccak", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.keccak_uint256s_bigend": { + "destination": "starkware.cairo.common.cairo_keccak.keccak.keccak_uint256s_bigend", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.nondet_bigint3": { + "destination": "starkware.cairo.common.cairo_secp.bigint.nondet_bigint3", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.reduce": { + "destination": "starkware.cairo.common.cairo_secp.field.reduce", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.uint256_to_bigint": { + "destination": "starkware.cairo.common.cairo_secp.bigint.uint256_to_bigint", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.unreduced_mul": { + "destination": "starkware.cairo.common.cairo_secp.field.unreduced_mul", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.unreduced_sqr": { + "destination": "starkware.cairo.common.cairo_secp.field.unreduced_sqr", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.unsigned_div_rem": { + "destination": "starkware.cairo.common.math.unsigned_div_rem", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.validate_reduced_field_element": { + "destination": "starkware.cairo.common.cairo_secp.field.validate_reduced_field_element", + "type": "alias" + }, + "starkware.cairo.common.cairo_secp.signature.verify_zero": { + "destination": "starkware.cairo.common.cairo_secp.field.verify_zero", + "type": "alias" + }, + "starkware.cairo.common.dict_access.DictAccess": { + "full_name": "starkware.cairo.common.dict_access.DictAccess", + "members": { + "key": { + "cairo_type": "felt", + "offset": 0 + }, + "new_value": { + "cairo_type": "felt", + "offset": 2 + }, + "prev_value": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.ec.EcOpBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", + "type": "alias" + }, + "starkware.cairo.common.ec.EcPoint": { + "destination": "starkware.cairo.common.ec_point.EcPoint", + "type": "alias" + }, + "starkware.cairo.common.ec.StarkCurve": { + "type": "namespace" + }, + "starkware.cairo.common.ec.StarkCurve.ALPHA": { + "type": "const", + "value": 1 + }, + "starkware.cairo.common.ec.StarkCurve.Args": { + "full_name": "starkware.cairo.common.ec.StarkCurve.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.ec.StarkCurve.BETA": { + "type": "const", + "value": -476910135076337975234679399815567221425937815956490878998147463828055613816 + }, + "starkware.cairo.common.ec.StarkCurve.GEN_X": { + "type": "const", + "value": 874739451078007766457464989774322083649278607533249481151382481072868806602 + }, + "starkware.cairo.common.ec.StarkCurve.GEN_Y": { + "type": "const", + "value": 152666792071518830868575557812948353041420400780739481342941381225525861407 + }, + "starkware.cairo.common.ec.StarkCurve.ImplicitArgs": { + "full_name": "starkware.cairo.common.ec.StarkCurve.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.ec.StarkCurve.ORDER": { + "type": "const", + "value": -96363463615509210819012598251359154898 + }, + "starkware.cairo.common.ec.StarkCurve.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.ec.StarkCurve.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.ec.is_quad_residue": { + "destination": "starkware.cairo.common.math.is_quad_residue", + "type": "alias" + }, + "starkware.cairo.common.ec_point.EcPoint": { + "full_name": "starkware.cairo.common.ec_point.EcPoint", + "members": { + "x": { + "cairo_type": "felt", + "offset": 0 + }, + "y": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.hash.HashBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.HashBuiltin", + "type": "alias" + }, + "starkware.cairo.common.keccak_state.KeccakBuiltinState": { + "full_name": "starkware.cairo.common.keccak_state.KeccakBuiltinState", + "members": { + "s0": { + "cairo_type": "felt", + "offset": 0 + }, + "s1": { + "cairo_type": "felt", + "offset": 1 + }, + "s2": { + "cairo_type": "felt", + "offset": 2 + }, + "s3": { + "cairo_type": "felt", + "offset": 3 + }, + "s4": { + "cairo_type": "felt", + "offset": 4 + }, + "s5": { + "cairo_type": "felt", + "offset": 5 + }, + "s6": { + "cairo_type": "felt", + "offset": 6 + }, + "s7": { + "cairo_type": "felt", + "offset": 7 + } + }, + "size": 8, + "type": "struct" + }, + "starkware.cairo.common.math.FALSE": { + "destination": "starkware.cairo.common.bool.FALSE", + "type": "alias" + }, + "starkware.cairo.common.math.TRUE": { + "destination": "starkware.cairo.common.bool.TRUE", + "type": "alias" + }, + "starkware.cairo.common.math.assert_le_felt": { + "decorators": [ + "known_ap_change" + ], + "pc": 18, + "type": "function" + }, + "starkware.cairo.common.math.assert_le_felt.Args": { + "full_name": "starkware.cairo.common.math.assert_le_felt.Args", + "members": { + "a": { + "cairo_type": "felt", + "offset": 0 + }, + "b": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.math.assert_le_felt.ImplicitArgs": { + "full_name": "starkware.cairo.common.math.assert_le_felt.ImplicitArgs", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_le_felt.PRIME_OVER_2_HIGH": { + "type": "const", + "value": 5316911983139663648412552867652567041 + }, + "starkware.cairo.common.math.assert_le_felt.PRIME_OVER_3_HIGH": { + "type": "const", + "value": 3544607988759775765608368578435044694 + }, + "starkware.cairo.common.math.assert_le_felt.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.math.assert_le_felt.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.math.assert_le_felt.a": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math.assert_le_felt.a", + "references": [ + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-4), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le_felt.b": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math.assert_le_felt.b", + "references": [ + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-3), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le_felt.range_check_ptr": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math.assert_le_felt.range_check_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-5), felt*)]" + }, + { + "ap_tracking_data": { + "group": 2, + "offset": 8 + }, + "pc": 28, + "value": "cast([fp + (-5)] + 4, felt)" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_le_felt.skip_exclude_a": { + "pc": 42, + "type": "label" + }, + "starkware.cairo.common.math.assert_le_felt.skip_exclude_b_minus_a": { + "pc": 54, + "type": "label" + }, + "starkware.cairo.common.math.assert_lt_felt": { + "decorators": [ + "known_ap_change" + ], + "pc": 63, + "type": "function" + }, + "starkware.cairo.common.math.assert_lt_felt.Args": { + "full_name": "starkware.cairo.common.math.assert_lt_felt.Args", + "members": { + "a": { + "cairo_type": "felt", + "offset": 0 + }, + "b": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.math.assert_lt_felt.ImplicitArgs": { + "full_name": "starkware.cairo.common.math.assert_lt_felt.ImplicitArgs", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math.assert_lt_felt.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.math.assert_lt_felt.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.math.assert_lt_felt.a": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math.assert_lt_felt.a", + "references": [ + { + "ap_tracking_data": { + "group": 3, + "offset": 0 + }, + "pc": 63, + "value": "[cast(fp + (-4), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math.assert_lt_felt.b": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math.assert_lt_felt.b", + "references": [ + { + "ap_tracking_data": { + "group": 3, + "offset": 0 + }, + "pc": 63, + "value": "[cast(fp + (-3), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math_cmp.RC_BOUND": { + "type": "const", + "value": 340282366920938463463374607431768211456 + }, + "starkware.cairo.common.math_cmp.assert_le_felt": { + "destination": "starkware.cairo.common.math.assert_le_felt", + "type": "alias" + }, + "starkware.cairo.common.math_cmp.assert_lt_felt": { + "destination": "starkware.cairo.common.math.assert_lt_felt", + "type": "alias" + }, + "starkware.cairo.common.math_cmp.is_le_felt": { + "decorators": [ + "known_ap_change" + ], + "pc": 128, + "type": "function" + }, + "starkware.cairo.common.math_cmp.is_le_felt.Args": { + "full_name": "starkware.cairo.common.math_cmp.is_le_felt.Args", + "members": { + "a": { + "cairo_type": "felt", + "offset": 0 + }, + "b": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.math_cmp.is_le_felt.ImplicitArgs": { + "full_name": "starkware.cairo.common.math_cmp.is_le_felt.ImplicitArgs", + "members": { + "range_check_ptr": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.math_cmp.is_le_felt.Return": { + "cairo_type": "felt", + "type": "type_definition" + }, + "starkware.cairo.common.math_cmp.is_le_felt.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.math_cmp.is_le_felt.a": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math_cmp.is_le_felt.a", + "references": [ + { + "ap_tracking_data": { + "group": 11, + "offset": 0 + }, + "pc": 128, + "value": "[cast(fp + (-4), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math_cmp.is_le_felt.b": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.math_cmp.is_le_felt.b", + "references": [ + { + "ap_tracking_data": { + "group": 11, + "offset": 0 + }, + "pc": 128, + "value": "[cast(fp + (-3), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.math_cmp.is_le_felt.not_le": { + "pc": 140, + "type": "label" + }, + "starkware.cairo.common.memcpy.memcpy": { + "decorators": [], + "pc": 3, + "type": "function" + }, + "starkware.cairo.common.memcpy.memcpy.Args": { + "full_name": "starkware.cairo.common.memcpy.memcpy.Args", + "members": { + "dst": { + "cairo_type": "felt*", + "offset": 0 + }, + "len": { + "cairo_type": "felt", + "offset": 2 + }, + "src": { + "cairo_type": "felt*", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.cairo.common.memcpy.memcpy.ImplicitArgs": { + "full_name": "starkware.cairo.common.memcpy.memcpy.ImplicitArgs", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.cairo.common.memcpy.memcpy.LoopFrame": { + "full_name": "starkware.cairo.common.memcpy.memcpy.LoopFrame", + "members": { + "dst": { + "cairo_type": "felt*", + "offset": 0 + }, + "src": { + "cairo_type": "felt*", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.memcpy.memcpy.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.memcpy.memcpy.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.memcpy.memcpy.continue_copying": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.memcpy.memcpy.continue_copying", + "references": [ + { + "ap_tracking_data": { + "group": 1, + "offset": 3 + }, + "pc": 10, + "value": "[cast(ap, felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.memcpy.memcpy.len": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.memcpy.memcpy.len", + "references": [ + { + "ap_tracking_data": { + "group": 1, + "offset": 0 + }, + "pc": 3, + "value": "[cast(fp + (-3), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.memcpy.memcpy.loop": { + "pc": 8, + "type": "label" + }, + "starkware.cairo.common.pow.assert_le": { + "destination": "starkware.cairo.common.math.assert_le", + "type": "alias" + }, + "starkware.cairo.common.pow.get_ap": { + "destination": "starkware.cairo.common.registers.get_ap", + "type": "alias" + }, + "starkware.cairo.common.pow.get_fp_and_pc": { + "destination": "starkware.cairo.common.registers.get_fp_and_pc", + "type": "alias" + }, + "starkware.cairo.common.registers.get_ap": { + "destination": "starkware.cairo.lang.compiler.lib.registers.get_ap", + "type": "alias" + }, + "starkware.cairo.common.registers.get_fp_and_pc": { + "destination": "starkware.cairo.lang.compiler.lib.registers.get_fp_and_pc", + "type": "alias" + }, + "starkware.cairo.common.signature.EcOpBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.EcOpBuiltin", + "type": "alias" + }, + "starkware.cairo.common.signature.EcPoint": { + "destination": "starkware.cairo.common.ec_point.EcPoint", + "type": "alias" + }, + "starkware.cairo.common.signature.FALSE": { + "destination": "starkware.cairo.common.bool.FALSE", + "type": "alias" + }, + "starkware.cairo.common.signature.SignatureBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.SignatureBuiltin", + "type": "alias" + }, + "starkware.cairo.common.signature.StarkCurve": { + "destination": "starkware.cairo.common.ec.StarkCurve", + "type": "alias" + }, + "starkware.cairo.common.signature.TRUE": { + "destination": "starkware.cairo.common.bool.TRUE", + "type": "alias" + }, + "starkware.cairo.common.signature.ec_add": { + "destination": "starkware.cairo.common.ec.ec_add", + "type": "alias" + }, + "starkware.cairo.common.signature.ec_mul": { + "destination": "starkware.cairo.common.ec.ec_mul", + "type": "alias" + }, + "starkware.cairo.common.signature.ec_sub": { + "destination": "starkware.cairo.common.ec.ec_sub", + "type": "alias" + }, + "starkware.cairo.common.signature.is_x_on_curve": { + "destination": "starkware.cairo.common.ec.is_x_on_curve", + "type": "alias" + }, + "starkware.cairo.common.signature.recover_y": { + "destination": "starkware.cairo.common.ec.recover_y", + "type": "alias" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature": { + "decorators": [], + "pc": 123, + "type": "function" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.Args": { + "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.Args", + "members": { + "message": { + "cairo_type": "felt", + "offset": 0 + }, + "public_key": { + "cairo_type": "felt", + "offset": 1 + }, + "signature_r": { + "cairo_type": "felt", + "offset": 2 + }, + "signature_s": { + "cairo_type": "felt", + "offset": 3 + } + }, + "size": 4, + "type": "struct" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.ImplicitArgs": { + "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.ImplicitArgs", + "members": { + "ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr": { + "cairo_type": "starkware.cairo.common.cairo_builtins.SignatureBuiltin*", + "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.ecdsa_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-7), starkware.cairo.common.cairo_builtins.SignatureBuiltin**)]" + }, + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 125, + "value": "cast([fp + (-7)] + 2, starkware.cairo.common.cairo_builtins.SignatureBuiltin*)" + } + ], + "type": "reference" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.signature_r", + "references": [ + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-4), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s": { + "cairo_type": "felt", + "full_name": "starkware.cairo.common.signature.verify_ecdsa_signature.signature_s", + "references": [ + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-3), felt*)]" + } + ], + "type": "reference" + }, + "starkware.cairo.common.uint256.ALL_ONES": { + "type": "const", + "value": 340282366920938463463374607431768211455 + }, + "starkware.cairo.common.uint256.BitwiseBuiltin": { + "destination": "starkware.cairo.common.cairo_builtins.BitwiseBuiltin", + "type": "alias" + }, + "starkware.cairo.common.uint256.HALF_SHIFT": { + "type": "const", + "value": 18446744073709551616 + }, + "starkware.cairo.common.uint256.SHIFT": { + "type": "const", + "value": 340282366920938463463374607431768211456 + }, + "starkware.cairo.common.uint256.Uint256": { + "full_name": "starkware.cairo.common.uint256.Uint256", + "members": { + "high": { + "cairo_type": "felt", + "offset": 1 + }, + "low": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.cairo.common.uint256.assert_in_range": { + "destination": "starkware.cairo.common.math.assert_in_range", + "type": "alias" + }, + "starkware.cairo.common.uint256.assert_le": { + "destination": "starkware.cairo.common.math.assert_le", + "type": "alias" + }, + "starkware.cairo.common.uint256.assert_nn_le": { + "destination": "starkware.cairo.common.math.assert_nn_le", + "type": "alias" + }, + "starkware.cairo.common.uint256.assert_not_zero": { + "destination": "starkware.cairo.common.math.assert_not_zero", + "type": "alias" + }, + "starkware.cairo.common.uint256.bitwise_and": { + "destination": "starkware.cairo.common.bitwise.bitwise_and", + "type": "alias" + }, + "starkware.cairo.common.uint256.bitwise_or": { + "destination": "starkware.cairo.common.bitwise.bitwise_or", + "type": "alias" + }, + "starkware.cairo.common.uint256.bitwise_xor": { + "destination": "starkware.cairo.common.bitwise.bitwise_xor", + "type": "alias" + }, + "starkware.cairo.common.uint256.get_ap": { + "destination": "starkware.cairo.common.registers.get_ap", + "type": "alias" + }, + "starkware.cairo.common.uint256.get_fp_and_pc": { + "destination": "starkware.cairo.common.registers.get_fp_and_pc", + "type": "alias" + }, + "starkware.cairo.common.uint256.is_le": { + "destination": "starkware.cairo.common.math_cmp.is_le", + "type": "alias" + }, + "starkware.cairo.common.uint256.pow": { + "destination": "starkware.cairo.common.pow.pow", + "type": "alias" + }, + "starkware.starknet.common.storage.ADDR_BOUND": { + "type": "const", + "value": -106710729501573572985208420194530329073740042555888586719489 + }, + "starkware.starknet.common.storage.MAX_STORAGE_ITEM_SIZE": { + "type": "const", + "value": 256 + }, + "starkware.starknet.common.storage.assert_250_bit": { + "destination": "starkware.cairo.common.math.assert_250_bit", + "type": "alias" + }, + "starkware.starknet.common.syscalls.CALL_CONTRACT_SELECTOR": { + "type": "const", + "value": 20853273475220472486191784820 + }, + "starkware.starknet.common.syscalls.CallContract": { + "full_name": "starkware.starknet.common.syscalls.CallContract", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.CallContractRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", + "offset": 5 + } + }, + "size": 7, + "type": "struct" + }, + "starkware.starknet.common.syscalls.CallContractRequest": { + "full_name": "starkware.starknet.common.syscalls.CallContractRequest", + "members": { + "calldata": { + "cairo_type": "felt*", + "offset": 4 + }, + "calldata_size": { + "cairo_type": "felt", + "offset": 3 + }, + "contract_address": { + "cairo_type": "felt", + "offset": 1 + }, + "function_selector": { + "cairo_type": "felt", + "offset": 2 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 5, + "type": "struct" + }, + "starkware.starknet.common.syscalls.CallContractResponse": { + "full_name": "starkware.starknet.common.syscalls.CallContractResponse", + "members": { + "retdata": { + "cairo_type": "felt*", + "offset": 1 + }, + "retdata_size": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.DELEGATE_CALL_SELECTOR": { + "type": "const", + "value": 21167594061783206823196716140 + }, + "starkware.starknet.common.syscalls.DELEGATE_L1_HANDLER_SELECTOR": { + "type": "const", + "value": 23274015802972845247556842986379118667122 + }, + "starkware.starknet.common.syscalls.DEPLOY_SELECTOR": { + "type": "const", + "value": 75202468540281 + }, + "starkware.starknet.common.syscalls.Deploy": { + "full_name": "starkware.starknet.common.syscalls.Deploy", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.DeployRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.DeployResponse", + "offset": 6 + } + }, + "size": 9, + "type": "struct" + }, + "starkware.starknet.common.syscalls.DeployRequest": { + "full_name": "starkware.starknet.common.syscalls.DeployRequest", + "members": { + "class_hash": { + "cairo_type": "felt", + "offset": 1 + }, + "constructor_calldata": { + "cairo_type": "felt*", + "offset": 4 + }, + "constructor_calldata_size": { + "cairo_type": "felt", + "offset": 3 + }, + "contract_address_salt": { + "cairo_type": "felt", + "offset": 2 + }, + "deploy_from_zero": { + "cairo_type": "felt", + "offset": 5 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 6, + "type": "struct" + }, + "starkware.starknet.common.syscalls.DeployResponse": { + "full_name": "starkware.starknet.common.syscalls.DeployResponse", + "members": { + "constructor_retdata": { + "cairo_type": "felt*", + "offset": 2 + }, + "constructor_retdata_size": { + "cairo_type": "felt", + "offset": 1 + }, + "contract_address": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.DictAccess": { + "destination": "starkware.cairo.common.dict_access.DictAccess", + "type": "alias" + }, + "starkware.starknet.common.syscalls.EMIT_EVENT_SELECTOR": { + "type": "const", + "value": 1280709301550335749748 + }, + "starkware.starknet.common.syscalls.EmitEvent": { + "full_name": "starkware.starknet.common.syscalls.EmitEvent", + "members": { + "data": { + "cairo_type": "felt*", + "offset": 4 + }, + "data_len": { + "cairo_type": "felt", + "offset": 3 + }, + "keys": { + "cairo_type": "felt*", + "offset": 2 + }, + "keys_len": { + "cairo_type": "felt", + "offset": 1 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 5, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GET_BLOCK_NUMBER_SELECTOR": { + "type": "const", + "value": 1448089106835523001438702345020786 + }, + "starkware.starknet.common.syscalls.GET_BLOCK_TIMESTAMP_SELECTOR": { + "type": "const", + "value": 24294903732626645868215235778792757751152 + }, + "starkware.starknet.common.syscalls.GET_CALLER_ADDRESS_SELECTOR": { + "type": "const", + "value": 94901967781393078444254803017658102643 + }, + "starkware.starknet.common.syscalls.GET_CONTRACT_ADDRESS_SELECTOR": { + "type": "const", + "value": 6219495360805491471215297013070624192820083 + }, + "starkware.starknet.common.syscalls.GET_SEQUENCER_ADDRESS_SELECTOR": { + "type": "const", + "value": 1592190833581991703053805829594610833820054387 + }, + "starkware.starknet.common.syscalls.GET_TX_INFO_SELECTOR": { + "type": "const", + "value": 1317029390204112103023 + }, + "starkware.starknet.common.syscalls.GET_TX_SIGNATURE_SELECTOR": { + "type": "const", + "value": 1448089128652340074717162277007973 + }, + "starkware.starknet.common.syscalls.GetBlockNumber": { + "full_name": "starkware.starknet.common.syscalls.GetBlockNumber", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetBlockNumberResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetBlockNumberRequest": { + "full_name": "starkware.starknet.common.syscalls.GetBlockNumberRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetBlockNumberResponse": { + "full_name": "starkware.starknet.common.syscalls.GetBlockNumberResponse", + "members": { + "block_number": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetBlockTimestamp": { + "full_name": "starkware.starknet.common.syscalls.GetBlockTimestamp", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetBlockTimestampRequest": { + "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetBlockTimestampResponse": { + "full_name": "starkware.starknet.common.syscalls.GetBlockTimestampResponse", + "members": { + "block_timestamp": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetCallerAddress": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddress", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetCallerAddressResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetCallerAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddressRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetCallerAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetCallerAddressResponse", + "members": { + "caller_address": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetContractAddress": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddress", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetContractAddressResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetContractAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddressRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetContractAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetContractAddressResponse", + "members": { + "contract_address": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetSequencerAddress": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddress", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetSequencerAddressRequest": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetSequencerAddressResponse": { + "full_name": "starkware.starknet.common.syscalls.GetSequencerAddressResponse", + "members": { + "sequencer_address": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxInfo": { + "full_name": "starkware.starknet.common.syscalls.GetTxInfo", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetTxInfoResponse", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxInfoRequest": { + "full_name": "starkware.starknet.common.syscalls.GetTxInfoRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxInfoResponse": { + "full_name": "starkware.starknet.common.syscalls.GetTxInfoResponse", + "members": { + "tx_info": { + "cairo_type": "starkware.starknet.common.syscalls.TxInfo*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxSignature": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignature", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.GetTxSignatureResponse", + "offset": 1 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxSignatureRequest": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignatureRequest", + "members": { + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.GetTxSignatureResponse": { + "full_name": "starkware.starknet.common.syscalls.GetTxSignatureResponse", + "members": { + "signature": { + "cairo_type": "felt*", + "offset": 1 + }, + "signature_len": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.LIBRARY_CALL_L1_HANDLER_SELECTOR": { + "type": "const", + "value": 436233452754198157705746250789557519228244616562 + }, + "starkware.starknet.common.syscalls.LIBRARY_CALL_SELECTOR": { + "type": "const", + "value": 92376026794327011772951660 + }, + "starkware.starknet.common.syscalls.LibraryCall": { + "full_name": "starkware.starknet.common.syscalls.LibraryCall", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.LibraryCallRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.CallContractResponse", + "offset": 5 + } + }, + "size": 7, + "type": "struct" + }, + "starkware.starknet.common.syscalls.LibraryCallRequest": { + "full_name": "starkware.starknet.common.syscalls.LibraryCallRequest", + "members": { + "calldata": { + "cairo_type": "felt*", + "offset": 4 + }, + "calldata_size": { + "cairo_type": "felt", + "offset": 3 + }, + "class_hash": { + "cairo_type": "felt", + "offset": 1 + }, + "function_selector": { + "cairo_type": "felt", + "offset": 2 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 5, + "type": "struct" + }, + "starkware.starknet.common.syscalls.SEND_MESSAGE_TO_L1_SELECTOR": { + "type": "const", + "value": 433017908768303439907196859243777073 + }, + "starkware.starknet.common.syscalls.STORAGE_READ_SELECTOR": { + "type": "const", + "value": 100890693370601760042082660 + }, + "starkware.starknet.common.syscalls.STORAGE_WRITE_SELECTOR": { + "type": "const", + "value": 25828017502874050592466629733 + }, + "starkware.starknet.common.syscalls.SendMessageToL1SysCall": { + "full_name": "starkware.starknet.common.syscalls.SendMessageToL1SysCall", + "members": { + "payload_ptr": { + "cairo_type": "felt*", + "offset": 3 + }, + "payload_size": { + "cairo_type": "felt", + "offset": 2 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + }, + "to_address": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 4, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageRead": { + "full_name": "starkware.starknet.common.syscalls.StorageRead", + "members": { + "request": { + "cairo_type": "starkware.starknet.common.syscalls.StorageReadRequest", + "offset": 0 + }, + "response": { + "cairo_type": "starkware.starknet.common.syscalls.StorageReadResponse", + "offset": 2 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageReadRequest": { + "full_name": "starkware.starknet.common.syscalls.StorageReadRequest", + "members": { + "address": { + "cairo_type": "felt", + "offset": 1 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageReadResponse": { + "full_name": "starkware.starknet.common.syscalls.StorageReadResponse", + "members": { + "value": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.StorageWrite": { + "full_name": "starkware.starknet.common.syscalls.StorageWrite", + "members": { + "address": { + "cairo_type": "felt", + "offset": 1 + }, + "selector": { + "cairo_type": "felt", + "offset": 0 + }, + "value": { + "cairo_type": "felt", + "offset": 2 + } + }, + "size": 3, + "type": "struct" + }, + "starkware.starknet.common.syscalls.TxInfo": { + "full_name": "starkware.starknet.common.syscalls.TxInfo", + "members": { + "account_contract_address": { + "cairo_type": "felt", + "offset": 1 + }, + "chain_id": { + "cairo_type": "felt", + "offset": 6 + }, + "max_fee": { + "cairo_type": "felt", + "offset": 2 + }, + "nonce": { + "cairo_type": "felt", + "offset": 7 + }, + "signature": { + "cairo_type": "felt*", + "offset": 4 + }, + "signature_len": { + "cairo_type": "felt", + "offset": 3 + }, + "transaction_hash": { + "cairo_type": "felt", + "offset": 5 + }, + "version": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 8, + "type": "struct" + }, + "starkware.starknet.common.syscalls.call_contract": { + "decorators": [], + "pc": 74, + "type": "function" + }, + "starkware.starknet.common.syscalls.call_contract.Args": { + "full_name": "starkware.starknet.common.syscalls.call_contract.Args", + "members": { + "calldata": { + "cairo_type": "felt*", + "offset": 3 + }, + "calldata_size": { + "cairo_type": "felt", + "offset": 2 + }, + "contract_address": { + "cairo_type": "felt", + "offset": 0 + }, + "function_selector": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 4, + "type": "struct" + }, + "starkware.starknet.common.syscalls.call_contract.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.call_contract.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.call_contract.Return": { + "cairo_type": "(retdata_size: felt, retdata: felt*)", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.call_contract.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.call_contract.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.call_contract.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 4, + "offset": 0 + }, + "pc": 74, + "value": "[cast(fp + (-7), felt**)]" + }, + { + "ap_tracking_data": { + "group": 4, + "offset": 1 + }, + "pc": 81, + "value": "cast([fp + (-7)] + 7, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.get_caller_address": { + "decorators": [], + "pc": 86, + "type": "function" + }, + "starkware.starknet.common.syscalls.get_caller_address.Args": { + "full_name": "starkware.starknet.common.syscalls.get_caller_address.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_caller_address.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.get_caller_address.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_caller_address.Return": { + "cairo_type": "(caller_address: felt)", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.get_caller_address.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.get_caller_address.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 5, + "offset": 0 + }, + "pc": 86, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 5, + "offset": 1 + }, + "pc": 89, + "value": "cast([fp + (-3)] + 2, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.get_contract_address": { + "decorators": [], + "pc": 93, + "type": "function" + }, + "starkware.starknet.common.syscalls.get_contract_address.Args": { + "full_name": "starkware.starknet.common.syscalls.get_contract_address.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_contract_address.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.get_contract_address.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_contract_address.Return": { + "cairo_type": "(contract_address: felt)", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.get_contract_address.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.get_contract_address.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 6, + "offset": 0 + }, + "pc": 93, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 6, + "offset": 1 + }, + "pc": 96, + "value": "cast([fp + (-3)] + 2, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.get_tx_info": { + "decorators": [], + "pc": 116, + "type": "function" + }, + "starkware.starknet.common.syscalls.get_tx_info.Args": { + "full_name": "starkware.starknet.common.syscalls.get_tx_info.Args", + "members": {}, + "size": 0, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_tx_info.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.get_tx_info.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.get_tx_info.Return": { + "cairo_type": "(tx_info: starkware.starknet.common.syscalls.TxInfo*)", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.get_tx_info.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.get_tx_info.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 9, + "offset": 0 + }, + "pc": 116, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 9, + "offset": 1 + }, + "pc": 119, + "value": "cast([fp + (-3)] + 2, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.storage_read": { + "decorators": [], + "pc": 100, + "type": "function" + }, + "starkware.starknet.common.syscalls.storage_read.Args": { + "full_name": "starkware.starknet.common.syscalls.storage_read.Args", + "members": { + "address": { + "cairo_type": "felt", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_read.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.storage_read.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_read.Return": { + "cairo_type": "(value: felt)", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.storage_read.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.storage_read.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.storage_read.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 7, + "offset": 0 + }, + "pc": 100, + "value": "[cast(fp + (-4), felt**)]" + }, + { + "ap_tracking_data": { + "group": 7, + "offset": 1 + }, + "pc": 104, + "value": "cast([fp + (-4)] + 3, felt*)" + } + ], + "type": "reference" + }, + "starkware.starknet.common.syscalls.storage_write": { + "decorators": [], + "pc": 108, + "type": "function" + }, + "starkware.starknet.common.syscalls.storage_write.Args": { + "full_name": "starkware.starknet.common.syscalls.storage_write.Args", + "members": { + "address": { + "cairo_type": "felt", + "offset": 0 + }, + "value": { + "cairo_type": "felt", + "offset": 1 + } + }, + "size": 2, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_write.ImplicitArgs": { + "full_name": "starkware.starknet.common.syscalls.storage_write.ImplicitArgs", + "members": { + "syscall_ptr": { + "cairo_type": "felt*", + "offset": 0 + } + }, + "size": 1, + "type": "struct" + }, + "starkware.starknet.common.syscalls.storage_write.Return": { + "cairo_type": "()", + "type": "type_definition" + }, + "starkware.starknet.common.syscalls.storage_write.SIZEOF_LOCALS": { + "type": "const", + "value": 0 + }, + "starkware.starknet.common.syscalls.storage_write.syscall_ptr": { + "cairo_type": "felt*", + "full_name": "starkware.starknet.common.syscalls.storage_write.syscall_ptr", + "references": [ + { + "ap_tracking_data": { + "group": 8, + "offset": 0 + }, + "pc": 108, + "value": "[cast(fp + (-5), felt**)]" + }, + { + "ap_tracking_data": { + "group": 8, + "offset": 1 + }, + "pc": 113, + "value": "cast([fp + (-5)] + 3, felt*)" + } + ], + "type": "reference" + } + }, + "main_scope": "__main__", + "prime": "0x800000000000011000000000000000000000000000000000000000000000001", + "reference_manager": { + "references": [ + { + "ap_tracking_data": { + "group": 1, + "offset": 0 + }, + "pc": 3, + "value": "[cast(fp + (-3), felt*)]" + }, + { + "ap_tracking_data": { + "group": 1, + "offset": 3 + }, + "pc": 10, + "value": "[cast(ap, felt*)]" + }, + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-4), felt*)]" + }, + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-3), felt*)]" + }, + { + "ap_tracking_data": { + "group": 2, + "offset": 0 + }, + "pc": 18, + "value": "[cast(fp + (-5), felt*)]" + }, + { + "ap_tracking_data": { + "group": 3, + "offset": 0 + }, + "pc": 63, + "value": "[cast(fp + (-4), felt*)]" + }, + { + "ap_tracking_data": { + "group": 3, + "offset": 0 + }, + "pc": 63, + "value": "[cast(fp + (-3), felt*)]" + }, + { + "ap_tracking_data": { + "group": 4, + "offset": 0 + }, + "pc": 74, + "value": "[cast(fp + (-7), felt**)]" + }, + { + "ap_tracking_data": { + "group": 5, + "offset": 0 + }, + "pc": 86, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 6, + "offset": 0 + }, + "pc": 93, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 7, + "offset": 0 + }, + "pc": 100, + "value": "[cast(fp + (-4), felt**)]" + }, + { + "ap_tracking_data": { + "group": 8, + "offset": 0 + }, + "pc": 108, + "value": "[cast(fp + (-5), felt**)]" + }, + { + "ap_tracking_data": { + "group": 9, + "offset": 0 + }, + "pc": 116, + "value": "[cast(fp + (-3), felt**)]" + }, + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-4), felt*)]" + }, + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-3), felt*)]" + }, + { + "ap_tracking_data": { + "group": 10, + "offset": 0 + }, + "pc": 123, + "value": "[cast(fp + (-7), starkware.cairo.common.cairo_builtins.SignatureBuiltin**)]" + }, + { + "ap_tracking_data": { + "group": 11, + "offset": 0 + }, + "pc": 128, + "value": "[cast(fp + (-4), felt*)]" + }, + { + "ap_tracking_data": { + "group": 11, + "offset": 0 + }, + "pc": 128, + "value": "[cast(fp + (-3), felt*)]" + } + ] + } + } } diff --git a/crates/katana/primitives/src/block.rs b/crates/katana/primitives/src/block.rs index fd9bf41236..671489c55d 100644 --- a/crates/katana/primitives/src/block.rs +++ b/crates/katana/primitives/src/block.rs @@ -1,7 +1,7 @@ use starknet::core::crypto::compute_hash_on_elements; use crate::contract::ContractAddress; -use crate::transaction::{TxHash, TxWithHash}; +use crate::transaction::{ExecutableTxWithHash, TxHash, TxWithHash}; use crate::version::Version; use crate::FieldElement; @@ -32,6 +32,7 @@ pub enum FinalityStatus { #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct PartialHeader { + pub number: BlockNumber, pub parent_hash: FieldElement, pub gas_prices: GasPrices, pub timestamp: u64, @@ -71,14 +72,10 @@ pub struct Header { } impl Header { - pub fn new( - partial_header: PartialHeader, - number: BlockNumber, - state_root: FieldElement, - ) -> Self { + pub fn new(partial_header: PartialHeader, state_root: FieldElement) -> Self { Self { - number, state_root, + number: partial_header.number, version: partial_header.version, timestamp: partial_header.timestamp, gas_prices: partial_header.gas_prices, @@ -109,7 +106,7 @@ impl Header { } /// Represents a Starknet full block. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Block { pub header: Header, @@ -187,3 +184,11 @@ impl From for BlockHashOrNumber { Self::Hash(hash) } } + +/// A block that can executed. This is a block whose transactions includes +/// all the necessary information to be executed. +#[derive(Debug, Clone)] +pub struct ExecutableBlock { + pub header: PartialHeader, + pub body: Vec, +} diff --git a/crates/katana/primitives/src/class.rs b/crates/katana/primitives/src/class.rs new file mode 100644 index 0000000000..610b58c3c6 --- /dev/null +++ b/crates/katana/primitives/src/class.rs @@ -0,0 +1,38 @@ +use cairo_lang_starknet::casm_contract_class::CasmContractClass; + +use crate::FieldElement; + +/// The canonical hash of a contract class. This is the identifier of a class. +pub type ClassHash = FieldElement; +/// The hash of a compiled contract class. +pub type CompiledClassHash = FieldElement; + +pub type SierraClass = starknet::core::types::contract::SierraClass; +pub type FlattenedSierraClass = starknet::core::types::FlattenedSierraClass; + +/// Deprecated legacy (Cairo 0) CASM class +pub type DeprecatedCompiledClass = ::starknet_api::deprecated_contract_class::ContractClass; + +/// Represents an executable Sierra program. +#[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SierraProgram { + pub program: cairo_lang_sierra::program::Program, + pub entry_points_by_type: cairo_lang_starknet::contract_class::ContractEntryPoints, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SierraCompiledClass { + pub casm: CasmContractClass, + pub sierra: SierraProgram, +} + +/// Executable contract class +#[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone, Eq, PartialEq, derive_more::From)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum CompiledClass { + Class(SierraCompiledClass), + Deprecated(DeprecatedCompiledClass), +} diff --git a/crates/katana/primitives/src/contract.rs b/crates/katana/primitives/src/contract.rs index eae4df0ab7..028bd8a95a 100644 --- a/crates/katana/primitives/src/contract.rs +++ b/crates/katana/primitives/src/contract.rs @@ -3,6 +3,7 @@ use std::fmt; use derive_more::Deref; use starknet::core::utils::normalize_address; +use crate::class::ClassHash; use crate::FieldElement; /// Represents the type for a contract storage key. @@ -10,17 +11,9 @@ pub type StorageKey = FieldElement; /// Represents the type for a contract storage value. pub type StorageValue = FieldElement; -/// The canonical hash of a contract class. This is the class hash value of a contract instance. -pub type ClassHash = FieldElement; -/// The hash of a compiled contract class. -pub type CompiledClassHash = FieldElement; - /// Represents the type for a contract nonce. pub type Nonce = FieldElement; -pub type SierraClass = starknet::core::types::contract::SierraClass; -pub type FlattenedSierraClass = starknet::core::types::FlattenedSierraClass; - /// Represents a contract address. #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Debug, Deref)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -59,13 +52,3 @@ pub struct GenericContractInfo { /// The hash of the contract class. pub class_hash: ClassHash, } - -/// Represents a runnable Starknet contract class (meaning, the program is runnable by the VM). -#[cfg(feature = "blockifier")] -pub type CompiledContractClass = ::blockifier::execution::contract_class::ContractClass; -/// V0 of the compiled contract class -#[cfg(feature = "blockifier")] -pub type CompiledContractClassV0 = ::blockifier::execution::contract_class::ContractClassV0; -/// V1 of the compiled contract class -#[cfg(feature = "blockifier")] -pub type CompiledContractClassV1 = ::blockifier::execution::contract_class::ContractClassV1; diff --git a/crates/katana/primitives/src/conversion/blockifier.rs b/crates/katana/primitives/src/conversion/blockifier.rs deleted file mode 100644 index 80751fb896..0000000000 --- a/crates/katana/primitives/src/conversion/blockifier.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! Translation layer for converting the primitive types to the execution engine types. - -use starknet::core::utils::parse_cairo_short_string; -use starknet_api::core::{ContractAddress, PatriciaKey}; -use starknet_api::hash::StarkHash; -use starknet_api::patricia_key; - -use crate::chain::ChainId; - -impl From for ContractAddress { - fn from(address: crate::contract::ContractAddress) -> Self { - Self(patricia_key!(address.0)) - } -} - -impl From for crate::contract::ContractAddress { - fn from(address: ContractAddress) -> Self { - Self((*address.0.key()).into()) - } -} - -impl From for starknet_api::core::ChainId { - fn from(chain_id: ChainId) -> Self { - let name: String = match chain_id { - ChainId::Named(named) => named.name().to_string(), - ChainId::Id(id) => parse_cairo_short_string(&id).expect("valid cairo string"), - }; - Self(name) - } -} - -#[cfg(test)] -mod tests { - use starknet::core::utils::parse_cairo_short_string; - - use crate::chain::{ChainId, NamedChainId}; - - #[test] - fn convert_chain_id() { - let mainnet = starknet_api::core::ChainId::from(ChainId::Named(NamedChainId::Mainnet)); - let goerli = starknet_api::core::ChainId::from(ChainId::Named(NamedChainId::Goerli)); - let sepolia = starknet_api::core::ChainId::from(ChainId::Named(NamedChainId::Sepolia)); - - assert_eq!(mainnet.0, parse_cairo_short_string(&NamedChainId::Mainnet.id()).unwrap()); - assert_eq!(goerli.0, parse_cairo_short_string(&NamedChainId::Goerli.id()).unwrap()); - assert_eq!(sepolia.0, parse_cairo_short_string(&NamedChainId::Sepolia.id()).unwrap()); - } -} diff --git a/crates/katana/primitives/src/conversion/mod.rs b/crates/katana/primitives/src/conversion/mod.rs index 00281f3728..0818b474ae 100644 --- a/crates/katana/primitives/src/conversion/mod.rs +++ b/crates/katana/primitives/src/conversion/mod.rs @@ -1,4 +1,2 @@ -#[cfg(feature = "blockifier")] -pub mod blockifier; #[cfg(feature = "rpc")] pub mod rpc; diff --git a/crates/katana/primitives/src/conversion/rpc.rs b/crates/katana/primitives/src/conversion/rpc.rs index fcb286d5e0..41d9836743 100644 --- a/crates/katana/primitives/src/conversion/rpc.rs +++ b/crates/katana/primitives/src/conversion/rpc.rs @@ -1,54 +1,40 @@ use std::collections::{BTreeMap, HashMap}; use std::io::{self, Read, Write}; use std::mem; -use std::str::FromStr; -use anyhow::{anyhow, Result}; -use blockifier::execution::contract_class::ContractClassV0; +use anyhow::{Context, Result}; use cairo_lang_starknet::casm_contract_class::CasmContractClass; -use cairo_vm::felt::Felt252; -use cairo_vm::serde::deserialize_program::{ - serialize_program_data, ApTracking, OffsetValue, ProgramJson, ValueAddress, -}; -use cairo_vm::types::instruction::Register; -use cairo_vm::types::program::Program; -use serde::{Deserialize, Serialize, Serializer}; -use serde_json::{json, Number}; +use serde::Deserialize; +use serde_json::json; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; pub use starknet::core::types::contract::legacy::{LegacyContractClass, LegacyProgram}; use starknet::core::types::contract::legacy::{ LegacyDebugInfo, LegacyFlowTrackingData, LegacyHint, LegacyIdentifier, LegacyReferenceManager, - RawLegacyAbiEntry, RawLegacyEntryPoints, }; pub use starknet::core::types::contract::CompiledClass; use starknet::core::types::{ - CompressedLegacyContractClass, ContractClass, LegacyContractEntryPoint, LegacyEntryPointsByType, + CompressedLegacyContractClass, ContractClass, FunctionStateMutability, LegacyContractAbiEntry, + LegacyContractEntryPoint, LegacyEntryPointsByType, LegacyEventAbiEntry, LegacyEventAbiType, + LegacyFunctionAbiEntry, LegacyFunctionAbiType, LegacyStructAbiEntry, LegacyStructAbiType, + LegacyStructMember, LegacyTypedParameter, +}; +use starknet_api::deprecated_contract_class::{ + ContractClassAbiEntry, EntryPoint, EntryPointType, TypedParameter, }; -use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointType}; -use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, CompiledContractClassV0, - FlattenedSierraClass, +use crate::class::{ + ClassHash, CompiledClassHash, DeprecatedCompiledClass, FlattenedSierraClass, + SierraCompiledClass, SierraProgram, }; use crate::FieldElement; -mod primitives { - pub use crate::contract::{CompiledContractClass, ContractAddress, Nonce}; - pub use crate::transaction::{DeclareTx, DeployAccountTx, InvokeTx, L1HandlerTx, Tx}; - pub use crate::FieldElement; -} - -use cairo_vm::serde::deserialize_program::{Attribute, BuiltinName, DebugInfo, HintParams, Member}; -use cairo_vm::types::relocatable::MaybeRelocatable; - -/// Converts the legacy inner compiled class type [CompiledContractClassV0] into its RPC equivalent +/// Converts the legacy inner compiled class type [DeprecatedCompiledClass] into its RPC equivalent /// [`ContractClass`]. pub fn legacy_inner_to_rpc_class( - legacy_contract_class: CompiledContractClassV0, + legacy_contract_class: DeprecatedCompiledClass, ) -> Result { - // Convert [EntryPointType] (blockifier type) into [LegacyEntryPointsByType] (RPC type) - fn to_rpc_legacy_entry_points_by_type( + fn to_rpc_entry_points( entries: &HashMap>, ) -> Result { fn collect_entry_points( @@ -57,7 +43,7 @@ pub fn legacy_inner_to_rpc_class( ) -> Result> { Ok(entries .get(entry_point_type) - .ok_or(anyhow!("Missing {entry_point_type:?} entry point",))? + .context(format!("Missing {entry_point_type:?} entry point"))? .iter() .map(|e| LegacyContractEntryPoint { offset: e.offset.0 as u64, @@ -73,37 +59,100 @@ pub fn legacy_inner_to_rpc_class( }) } - let entry_points_by_type = - to_rpc_legacy_entry_points_by_type(&legacy_contract_class.entry_points_by_type)?; + fn convert_typed_param(param: Vec) -> Vec { + param + .into_iter() + .map(|param| LegacyTypedParameter { name: param.name, r#type: param.r#type }) + .collect() + } + + fn convert_abi_entry(abi: ContractClassAbiEntry) -> LegacyContractAbiEntry { + match abi { + ContractClassAbiEntry::Function(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::Function, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } - let compressed_program = compress_legacy_program_data(legacy_contract_class.program.clone())?; + ContractClassAbiEntry::Event(a) => LegacyContractAbiEntry::Event(LegacyEventAbiEntry { + name: a.name, + r#type: LegacyEventAbiType::Event, + data: convert_typed_param(a.data), + keys: convert_typed_param(a.keys), + }), + + ContractClassAbiEntry::Constructor(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::Constructor, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } + + ContractClassAbiEntry::Struct(a) => { + LegacyContractAbiEntry::Struct(LegacyStructAbiEntry { + name: a.name, + size: a.size as u64, + r#type: LegacyStructAbiType::Struct, + members: a + .members + .into_iter() + .map(|m| LegacyStructMember { + name: m.param.name, + offset: m.offset as u64, + r#type: m.param.r#type, + }) + .collect(), + }) + } - Ok(ContractClass::Legacy(CompressedLegacyContractClass { - program: compressed_program, - abi: None, - entry_points_by_type, - })) + ContractClassAbiEntry::L1Handler(a) => { + LegacyContractAbiEntry::Function(LegacyFunctionAbiEntry { + name: a.name, + r#type: LegacyFunctionAbiType::L1Handler, + inputs: convert_typed_param(a.inputs), + outputs: convert_typed_param(a.outputs), + state_mutability: a.state_mutability.map(|_| FunctionStateMutability::View), + }) + } + } + } + + fn convert_abi(abi: Option>) -> Option> { + abi.map(|abi| abi.into_iter().map(convert_abi_entry).collect()) + } + + let abi = convert_abi(legacy_contract_class.abi); + let program = compress_legacy_program_data(legacy_contract_class.program.clone())?; + let entry_points_by_type = to_rpc_entry_points(&legacy_contract_class.entry_points_by_type)?; + + Ok(ContractClass::Legacy(CompressedLegacyContractClass { abi, program, entry_points_by_type })) } -/// Convert the given [`FlattenedSierraClass`] into the inner compiled class type -/// [`CompiledContractClass`] along with its class hashes. +/// Convert the given [FlattenedSierraClass] into the inner compiled class type +/// [CompiledClass](crate::class::CompiledClass) along with its class hashes. pub fn flattened_sierra_to_compiled_class( contract_class: &FlattenedSierraClass, -) -> Result<(ClassHash, CompiledClassHash, CompiledContractClass)> { +) -> Result<(ClassHash, CompiledClassHash, crate::class::CompiledClass)> { let class_hash = contract_class.class_hash(); - let contract_class = rpc_to_cairo_contract_class(contract_class)?; - let casm_contract = CasmContractClass::from_contract_class(contract_class, true)?; + let class = rpc_to_cairo_contract_class(contract_class)?; + + let program = class.extract_sierra_program()?; + let entry_points_by_type = class.entry_points_by_type.clone(); + let sierra = SierraProgram { program, entry_points_by_type }; - // compute compiled class hash - let res = serde_json::to_string(&casm_contract)?; - let compiled_class: CompiledClass = serde_json::from_str(&res)?; + let casm = CasmContractClass::from_contract_class(class, true)?; + let compiled_hash = FieldElement::from_bytes_be(&casm.compiled_class_hash().to_be_bytes())?; - Ok(( - class_hash, - compiled_class.class_hash()?, - CompiledContractClass::V1(casm_contract.try_into()?), - )) + let class = crate::class::CompiledClass::Class(SierraCompiledClass { casm, sierra }); + Ok((class_hash, compiled_hash, class)) } /// Compute the compiled class hash from the given [`FlattenedSierraClass`]. @@ -117,65 +166,20 @@ pub fn compiled_class_hash_from_flattened_sierra_class( } /// Converts a legacy RPC compiled contract class [CompressedLegacyContractClass] type to the inner -/// compiled class type [CompiledContractClass] along with its class hash. -pub fn legacy_rpc_to_inner_compiled_class( +/// compiled class type [CompiledClass](crate::class::CompiledClass) along with its class hash. +pub fn legacy_rpc_to_compiled_class( compressed_legacy_contract: &CompressedLegacyContractClass, -) -> Result<(ClassHash, CompiledContractClass)> { +) -> Result<(ClassHash, crate::class::CompiledClass)> { let class_json = json!({ "abi": compressed_legacy_contract.abi.clone().unwrap_or_default(), "entry_points_by_type": compressed_legacy_contract.entry_points_by_type, "program": decompress_legacy_program_data(&compressed_legacy_contract.program)?, }); - #[allow(unused)] - #[derive(Deserialize)] - struct LegacyAttribute { - #[serde(default)] - accessible_scopes: Vec, - end_pc: u64, - flow_tracking_data: Option, - name: String, - start_pc: u64, - value: String, - } - - #[allow(unused)] - #[serde_as] - #[derive(Deserialize)] - pub struct LegacyProgram { - attributes: Option>, - builtins: Vec, - compiler_version: Option, - #[serde_as(as = "Vec")] - data: Vec, - debug_info: Option, - hints: BTreeMap>, - identifiers: BTreeMap, - main_scope: String, - prime: String, - reference_manager: LegacyReferenceManager, - } - - #[allow(unused)] - #[derive(Deserialize)] - struct LegacyContractClassJson { - abi: Vec, - entry_points_by_type: RawLegacyEntryPoints, - program: LegacyProgram, - } - - // SAFETY: `LegacyContractClassJson` MUST maintain same memory layout as `LegacyContractClass`. - // This would only work if the fields are in the same order and have the same size. Though, - // both types are using default Rust repr, which means there is no guarantee by the compiler - // that the memory layout of both types will be the same despite comprised of the same - // fields and types. - let class: LegacyContractClassJson = serde_json::from_value(class_json.clone())?; - let class: LegacyContractClass = unsafe { mem::transmute(class) }; + let deprecated_class: DeprecatedCompiledClass = serde_json::from_value(class_json.clone())?; + let class_hash = serde_json::from_value::(class_json)?.class_hash()?; - let inner_class: ContractClassV0 = serde_json::from_value(class_json)?; - let class_hash = class.class_hash()?; - - Ok((class_hash, CompiledContractClass::V0(inner_class))) + Ok((class_hash, crate::class::CompiledClass::Deprecated(deprecated_class))) } /// Converts `starknet-rs` RPC [FlattenedSierraClass] type to Cairo's @@ -197,82 +201,11 @@ fn rpc_to_cairo_contract_class( }) } -fn compress_legacy_program_data(legacy_program: Program) -> Result, io::Error> { - fn felt_as_dec_str( - value: &Option, - serializer: S, - ) -> Result { - let dec_str = format!("{}", value.clone().unwrap_or_default().to_signed_felt()); - let number = Number::from_str(&dec_str).expect("valid number"); - number.serialize(serializer) - } - - fn value_address_in_str_format( - value_address: &ValueAddress, - serializer: S, - ) -> Result { - serializer.serialize_str(&parse_value_address_to_str(value_address.clone())) - } - - fn zero_if_none(pc: &Option, serializer: S) -> Result { - serializer.serialize_u64(pc.as_ref().map_or(0, |x| *x as u64)) - } - - #[derive(Serialize)] - struct Identifier { - #[serde(skip_serializing_if = "Option::is_none")] - pc: Option, - #[serde(rename = "type")] - #[serde(skip_serializing_if = "Option::is_none")] - type_: Option, - #[serde(serialize_with = "felt_as_dec_str")] - #[serde(skip_serializing_if = "Option::is_none")] - value: Option, - #[serde(skip_serializing_if = "Option::is_none")] - full_name: Option, - #[serde(skip_serializing_if = "Option::is_none")] - members: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - cairo_type: Option, - } - - #[derive(Serialize)] - struct Reference { - ap_tracking_data: ApTracking, - #[serde(serialize_with = "zero_if_none")] - pc: Option, - #[serde(rename(serialize = "value"))] - #[serde(serialize_with = "value_address_in_str_format")] - value_address: ValueAddress, - } - - #[derive(Serialize)] - struct ReferenceManager { - references: Vec, - } +fn compress_legacy_program_data( + legacy_program: starknet_api::deprecated_contract_class::Program, +) -> Result, io::Error> { + let bytes = serde_json::to_vec(&legacy_program)?; - #[derive(Serialize)] - struct SerializableProgramJson { - prime: String, - builtins: Vec, - #[serde(serialize_with = "serialize_program_data")] - data: Vec, - identifiers: HashMap, - hints: BTreeMap>, - reference_manager: ReferenceManager, - attributes: Vec, - debug_info: Option, - } - - // SAFETY: `SerializableProgramJson` MUST maintain same memory layout as `ProgramJson`. This - // would only work if the fields are in the same order and have the same size. Though, both - // types are using default Rust repr, which means there is no guarantee by the compiler that the - // memory layout of both types will be the same despite comprised of the same fields and - // types. - let program: ProgramJson = ProgramJson::from(legacy_program); - let program: SerializableProgramJson = unsafe { mem::transmute(program) }; - - let bytes = serde_json::to_vec(&program)?; let mut gzip_encoder = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::fast()); Write::write_all(&mut gzip_encoder, &bytes)?; gzip_encoder.finish() @@ -293,6 +226,7 @@ fn decompress_legacy_program_data(data: &[u8]) -> Result Result String { - fn handle_offset_ref(offset: i32, str: &mut String) { - if offset == 0 { - return; - } - - str.push_str(" + "); - str.push_str(&if offset.is_negative() { format!("({offset})") } else { offset.to_string() }) - } - - fn handle_offset_val(value: OffsetValue, str: &mut String) { - match value { - OffsetValue::Reference(rx, offset, deref) => { - let mut tmp = String::from(match rx { - Register::FP => "fp", - Register::AP => "ap", - }); - - handle_offset_ref(offset, &mut tmp); - - if deref { - str.push_str(&format!("[{tmp}]")); - } else { - str.push_str(&tmp); - } - } - - OffsetValue::Value(value) => handle_offset_ref(value, str), - - OffsetValue::Immediate(value) => { - if value == Felt252::from(0u32) { - return; - } - - str.push_str(" + "); - str.push_str(&value.to_string()); - } - } - } - - let mut str = String::new(); - let is_value: bool; - - if let OffsetValue::Immediate(_) = value_address.offset2 { - is_value = false; - } else { - is_value = true; - } - - handle_offset_val(value_address.offset1, &mut str); - handle_offset_val(value_address.offset2, &mut str); - - str.push_str(", "); - str.push_str(&value_address.value_type); - - if is_value { - str.push('*'); - } - - str = format!("cast({str})"); - - if value_address.dereference { - str = format!("[{str}]"); - } - - str -} - #[cfg(test)] mod tests { + use starknet::core::types::ContractClass; - use super::{legacy_inner_to_rpc_class, legacy_rpc_to_inner_compiled_class}; - use crate::utils::class::parse_compiled_class_v0; + use super::{legacy_inner_to_rpc_class, legacy_rpc_to_compiled_class}; + use crate::class::{CompiledClass, DeprecatedCompiledClass}; + use crate::genesis::constant::DEFAULT_OZ_ACCOUNT_CONTRACT; + use crate::utils::class::parse_deprecated_compiled_class; - // There are some discrepancies between the legacy RPC and the inner compiled class types which - // results in some data lost during the conversion. Therefore, we are unable to assert for - // equality between the original and the converted class. Instead, we assert that the conversion - // is successful and that the converted class can be converted back #[test] fn legacy_rpc_to_inner_and_back() { - let class_json = include_str!("../../contracts/compiled/account.json"); - let class = parse_compiled_class_v0(class_json).unwrap(); + let json = include_str!("../../contracts/compiled/account.json"); + let json = serde_json::from_str(json).unwrap(); + let class: DeprecatedCompiledClass = parse_deprecated_compiled_class(json).unwrap(); - let Ok(ContractClass::Legacy(compressed_legacy_class)) = legacy_inner_to_rpc_class(class) + let Ok(ContractClass::Legacy(compressed_legacy_class)) = + legacy_inner_to_rpc_class(class.clone()) else { panic!("Expected legacy class"); }; - legacy_rpc_to_inner_compiled_class(&compressed_legacy_class).unwrap(); + let (_, converted_class) = legacy_rpc_to_compiled_class(&compressed_legacy_class).unwrap(); + + let CompiledClass::Deprecated(converted) = converted_class else { panic!("invalid class") }; + + assert_eq!(class.abi, converted.abi); + assert_eq!(class.program, converted.program); + assert_eq!(class.entry_points_by_type, converted.entry_points_by_type); + } + + #[test] + fn flattened_sierra_class_to_compiled_class() { + let sierra = DEFAULT_OZ_ACCOUNT_CONTRACT.clone().flatten().unwrap(); + assert!(super::flattened_sierra_to_compiled_class(&sierra).is_ok()); } } diff --git a/crates/katana/primitives/src/event.rs b/crates/katana/primitives/src/event.rs index ebe08293cd..4fbbc470e9 100644 --- a/crates/katana/primitives/src/event.rs +++ b/crates/katana/primitives/src/event.rs @@ -1,6 +1,16 @@ use core::fmt; use std::num::ParseIntError; +use crate::FieldElement; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OrderedEvent { + pub order: u64, + pub keys: Vec, + pub data: Vec, +} + #[derive(PartialEq, Eq, Debug, Default)] pub struct ContinuationToken { pub block_n: u64, diff --git a/crates/katana/primitives/src/fee.rs b/crates/katana/primitives/src/fee.rs new file mode 100644 index 0000000000..e43686eeb4 --- /dev/null +++ b/crates/katana/primitives/src/fee.rs @@ -0,0 +1,14 @@ +use starknet::core::types::PriceUnit; + +/// Information regarding the fee and gas usages of a transaction. +#[derive(Debug, Clone)] +pub struct TxFeeInfo { + /// The total amount of L1 gas consumed by the transaction. + pub gas_consumed: u128, + /// The L1 gas price at the time of the transaction execution. + pub gas_price: u128, + /// The fee used by the transaction. + pub overall_fee: u128, + /// The type of fee used to pay for the transaction, depending on the transaction type. + pub unit: PriceUnit, +} diff --git a/crates/katana/primitives/src/genesis/allocation.rs b/crates/katana/primitives/src/genesis/allocation.rs index 81cf25abbd..fa5fd2a07c 100644 --- a/crates/katana/primitives/src/genesis/allocation.rs +++ b/crates/katana/primitives/src/genesis/allocation.rs @@ -11,7 +11,8 @@ use starknet::core::utils::get_contract_address; use starknet::signers::SigningKey; use super::constant::DEFAULT_OZ_ACCOUNT_CONTRACT_CLASS_HASH; -use crate::contract::{ClassHash, ContractAddress, StorageKey, StorageValue}; +use crate::class::ClassHash; +use crate::contract::{ContractAddress, StorageKey, StorageValue}; use crate::FieldElement; /// Represents a contract allocation in the genesis block. diff --git a/crates/katana/primitives/src/genesis/constant.rs b/crates/katana/primitives/src/genesis/constant.rs index d7dd569b91..16d8019b85 100644 --- a/crates/katana/primitives/src/genesis/constant.rs +++ b/crates/katana/primitives/src/genesis/constant.rs @@ -1,9 +1,8 @@ use lazy_static::lazy_static; use starknet::core::utils::get_storage_var_address; -use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, SierraClass, StorageKey, -}; +use crate::class::{ClassHash, CompiledClass, CompiledClassHash, SierraClass}; +use crate::contract::{ContractAddress, StorageKey}; use crate::utils::class::{parse_compiled_class, parse_sierra_class}; use crate::FieldElement; @@ -126,14 +125,15 @@ pub const DEFAULT_OZ_ACCOUNT_CONTRACT_COMPILED_CLASS_HASH: CompiledClassHash = lazy_static! { // Default fee token contract - pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/erc20.json")).unwrap(); + // pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/erc20.json")).unwrap(); + pub static ref DEFAULT_LEGACY_ERC20_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/erc20.json")); // Default universal deployer - pub static ref DEFAULT_LEGACY_UDC_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/universal_deployer.json")).unwrap(); + pub static ref DEFAULT_LEGACY_UDC_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/universal_deployer.json")); // Default account contract pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT: SierraClass = parse_sierra_class(include_str!("../../contracts/compiled/oz_account_080.json")).unwrap(); - pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT_CASM: CompiledContractClass = parse_compiled_class(include_str!("../../contracts/compiled/oz_account_080.json")).unwrap(); + pub static ref DEFAULT_OZ_ACCOUNT_CONTRACT_CASM: CompiledClass = read_compiled_class_artifact(include_str!("../../contracts/compiled/oz_account_080.json")); } @@ -144,3 +144,8 @@ lazy_static! { pub(super) fn get_fee_token_balance_base_storage_address(address: ContractAddress) -> FieldElement { get_storage_var_address("ERC20_balances", &[address.into()]).unwrap() } + +fn read_compiled_class_artifact(artifact: &str) -> CompiledClass { + let value = serde_json::from_str(artifact).unwrap(); + parse_compiled_class(value).unwrap() +} diff --git a/crates/katana/primitives/src/genesis/json.rs b/crates/katana/primitives/src/genesis/json.rs index 11f445575a..3efc140fa2 100644 --- a/crates/katana/primitives/src/genesis/json.rs +++ b/crates/katana/primitives/src/genesis/json.rs @@ -11,8 +11,7 @@ use std::str::FromStr; use std::sync::Arc; use base64::prelude::*; -use cairo_lang_starknet::casm_contract_class::{CasmContractClass, StarknetSierraCompilationError}; -use cairo_lang_starknet::contract_class::ContractClass; +use cairo_lang_starknet::casm_contract_class::StarknetSierraCompilationError; use cairo_vm::types::errors::program_errors::ProgramError; use ethers::types::U256; use rayon::prelude::*; @@ -37,11 +36,10 @@ use super::constant::{ }; use super::{FeeTokenConfig, Genesis, GenesisAllocation, UniversalDeployerConfig}; use crate::block::{BlockHash, BlockNumber, GasPrices}; -use crate::contract::{ - ClassHash, CompiledContractClass, CompiledContractClassV0, CompiledContractClassV1, - ContractAddress, SierraClass, StorageKey, StorageValue, -}; +use crate::class::{ClassHash, CompiledClass, SierraClass}; +use crate::contract::{ContractAddress, StorageKey, StorageValue}; use crate::genesis::GenesisClass; +use crate::utils::class::{parse_compiled_class_v1, parse_deprecated_compiled_class}; use crate::FieldElement; type Object = Map; @@ -282,28 +280,24 @@ impl TryFrom for Genesis { let (class_hash, compiled_class_hash, sierra, casm) = match sierra { Ok(sierra) => { - let casm: ContractClass = serde_json::from_value(artifact)?; - let casm = CasmContractClass::from_contract_class(casm, true)?; + let class = parse_compiled_class_v1(artifact)?; // check if the class hash is provided, otherwise compute it from the // artifacts let class_hash = class_hash.unwrap_or(sierra.class_hash()?); - let compiled_hash = casm.compiled_class_hash().to_be_bytes(); + let compiled_hash = class.casm.compiled_class_hash().to_be_bytes(); ( class_hash, FieldElement::from_bytes_be(&compiled_hash)?, Some(Arc::new(sierra.flatten()?)), - Arc::new(CompiledContractClass::V1(CompiledContractClassV1::try_from( - casm, - )?)), + Arc::new(CompiledClass::Class(class)), ) } // if the artifact is not a sierra contract, we check if it's a legacy contract Err(_) => { - let casm: CompiledContractClassV0 = - serde_json::from_value(artifact.clone())?; + let casm = parse_deprecated_compiled_class(artifact.clone())?; let class_hash = if let Some(class_hash) = class_hash { class_hash @@ -313,7 +307,7 @@ impl TryFrom for Genesis { casm.class_hash()? }; - (class_hash, class_hash, None, Arc::new(CompiledContractClass::V0(casm))) + (class_hash, class_hash, None, Arc::new(CompiledClass::Deprecated(casm))) } }; diff --git a/crates/katana/primitives/src/genesis/mod.rs b/crates/katana/primitives/src/genesis/mod.rs index 52d6e18fb4..5b072d196e 100644 --- a/crates/katana/primitives/src/genesis/mod.rs +++ b/crates/katana/primitives/src/genesis/mod.rs @@ -24,10 +24,8 @@ use self::constant::{ OZ_ACCOUNT_CONTRACT_PUBKEY_STORAGE_SLOT, }; use crate::block::{Block, BlockHash, BlockNumber, GasPrices, Header}; -use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - StorageKey, StorageValue, -}; +use crate::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use crate::contract::{ContractAddress, StorageKey, StorageValue}; use crate::state::StateUpdatesWithDeclaredClasses; use crate::utils::split_u256; use crate::version::CURRENT_STARKNET_VERSION; @@ -61,7 +59,7 @@ pub struct GenesisClass { pub compiled_class_hash: CompiledClassHash, /// The casm class definition. #[serde(skip_serializing)] - pub casm: Arc, + pub casm: Arc, /// The sierra class definition. #[serde(skip_serializing)] pub sierra: Option>, diff --git a/crates/katana/primitives/src/lib.rs b/crates/katana/primitives/src/lib.rs index 8ad19bdd5a..de95663047 100644 --- a/crates/katana/primitives/src/lib.rs +++ b/crates/katana/primitives/src/lib.rs @@ -1,10 +1,14 @@ pub mod block; pub mod chain; +pub mod class; pub mod contract; pub mod env; pub mod event; +pub mod fee; pub mod genesis; +pub mod message; pub mod receipt; +pub mod trace; pub mod transaction; pub mod version; diff --git a/crates/katana/primitives/src/message.rs b/crates/katana/primitives/src/message.rs new file mode 100644 index 0000000000..4772c0e048 --- /dev/null +++ b/crates/katana/primitives/src/message.rs @@ -0,0 +1,11 @@ +use crate::contract::ContractAddress; +use crate::FieldElement; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OrderedL2ToL1Message { + pub order: u64, + pub from_address: ContractAddress, + pub to_address: FieldElement, + pub payload: Vec, +} diff --git a/crates/katana/primitives/src/receipt.rs b/crates/katana/primitives/src/receipt.rs index a41f3b7773..2223115e61 100644 --- a/crates/katana/primitives/src/receipt.rs +++ b/crates/katana/primitives/src/receipt.rs @@ -109,11 +109,16 @@ impl Receipt { /// /// A transaction is reverted if the `revert_error` field in the receipt is not `None`. pub fn is_reverted(&self) -> bool { + self.revert_reason().is_some() + } + + /// Returns the revert reason if the transaction is reverted. + pub fn revert_reason(&self) -> Option<&str> { match self { - Receipt::Invoke(rct) => rct.revert_error.is_some(), - Receipt::Declare(rct) => rct.revert_error.is_some(), - Receipt::L1Handler(rct) => rct.revert_error.is_some(), - Receipt::DeployAccount(rct) => rct.revert_error.is_some(), + Receipt::Invoke(rct) => rct.revert_error.as_deref(), + Receipt::Declare(rct) => rct.revert_error.as_deref(), + Receipt::L1Handler(rct) => rct.revert_error.as_deref(), + Receipt::DeployAccount(rct) => rct.revert_error.as_deref(), } } diff --git a/crates/katana/primitives/src/state.rs b/crates/katana/primitives/src/state.rs index 2c67c062b9..16b80769f0 100644 --- a/crates/katana/primitives/src/state.rs +++ b/crates/katana/primitives/src/state.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; -use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - Nonce, StorageKey, StorageValue, -}; +use crate::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use crate::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; /// State updates. /// @@ -29,5 +27,5 @@ pub struct StateUpdatesWithDeclaredClasses { /// A mapping of class hashes to their sierra classes definition. pub declared_sierra_classes: HashMap, /// A mapping of class hashes to their compiled classes definition. - pub declared_compiled_classes: HashMap, + pub declared_compiled_classes: HashMap, } diff --git a/crates/katana/primitives/src/trace.rs b/crates/katana/primitives/src/trace.rs new file mode 100644 index 0000000000..1349e10358 --- /dev/null +++ b/crates/katana/primitives/src/trace.rs @@ -0,0 +1,88 @@ +use std::collections::{HashMap, HashSet}; + +use crate::class::ClassHash; +use crate::contract::ContractAddress; +use crate::event::OrderedEvent; +use crate::message::OrderedL2ToL1Message; +use crate::FieldElement; + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct TxExecInfo { + /// Transaction validation call info; [None] for `L1Handler`. + pub validate_call_info: Option, + /// Transaction execution call info; [None] for `Declare`. + pub execute_call_info: Option, + /// Fee transfer call info; [None] for `L1Handler`. + pub fee_transfer_call_info: Option, + /// The actual fee that was charged (in Wei). + pub actual_fee: u128, + /// Actual execution resources the transaction is charged for, + /// including L1 gas and additional OS resources estimation. + pub actual_resources: HashMap, + /// Error string for reverted transactions; [None] if transaction execution was successful. + pub revert_error: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ExecutionResources { + pub n_steps: u64, + pub n_memory_holes: u64, + pub builtin_instance_counter: HashMap, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum CallType { + Call, + Delegate, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum EntryPointType { + External, + L1Handler, + Constructor, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CallInfo { + /// The contract address which the call is initiated from. + pub caller_address: ContractAddress, + /// The call type. + pub call_type: CallType, + /// The contract address. + pub contract_address: ContractAddress, + /// The address where the code is being executed. + /// Optional, since there is no address to the code implementation in a delegate call. + pub code_address: Option, + /// The class hash, not given if it can be deduced from the storage address. + pub class_hash: Option, + /// The entry point selector. + pub entry_point_selector: FieldElement, + /// The entry point type. + pub entry_point_type: EntryPointType, + /// The data used as the input to the execute entry point. + pub calldata: Vec, + /// The data returned by the entry point execution. + pub retdata: Vec, + /// The resources used by the execution. + pub execution_resources: ExecutionResources, + /// The list of ordered events generated by the execution. + pub events: Vec, + /// The list of ordered l2 to l1 messages generated by the execution. + pub l2_to_l1_messages: Vec, + /// The list of storage addresses being read during the execution. + pub storage_read_values: Vec, + /// The list of storage addresses being accessed during the execution. + pub accessed_storage_keys: HashSet, + /// The list of inner calls triggered by the current call. + pub inner_calls: Vec, + /// The total gas consumed by the call. + pub gas_consumed: u128, + /// True if the execution has failed, false otherwise. + pub failed: bool, +} diff --git a/crates/katana/primitives/src/transaction.rs b/crates/katana/primitives/src/transaction.rs index 76b3c4671b..90a8d7c9be 100644 --- a/crates/katana/primitives/src/transaction.rs +++ b/crates/katana/primitives/src/transaction.rs @@ -3,10 +3,8 @@ use ethers::types::H256; use starknet::core::types::{DataAvailabilityMode, ResourceBoundsMapping}; use crate::chain::ChainId; -use crate::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - Nonce, -}; +use crate::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use crate::contract::{ContractAddress, Nonce}; use crate::utils::transaction::{ compute_declare_v1_tx_hash, compute_declare_v2_tx_hash, compute_declare_v3_tx_hash, compute_deploy_account_v1_tx_hash, compute_deploy_account_v3_tx_hash, @@ -16,7 +14,7 @@ use crate::{utils, FieldElement}; /// The hash of a transaction. pub type TxHash = FieldElement; -/// The sequential number for all the transactions.. +/// The sequential number for all the transactions. pub type TxNumber = u64; #[derive(Debug, Clone, PartialEq, Eq)] @@ -103,7 +101,7 @@ pub struct DeclareTxWithClass { /// The Sierra class, if any. pub sierra_class: Option, /// The compiled contract class. - pub compiled_class: CompiledContractClass, + pub compiled_class: CompiledClass, /// The raw transaction. #[deref] #[as_ref] @@ -114,7 +112,7 @@ impl DeclareTxWithClass { pub fn new_with_classes( transaction: DeclareTx, sierra_class: FlattenedSierraClass, - compiled_class: CompiledContractClass, + compiled_class: CompiledClass, ) -> Self { Self { sierra_class: Some(sierra_class), compiled_class, transaction } } @@ -350,7 +348,7 @@ impl DeclareTx { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct L1HandlerTx { pub nonce: Nonce, diff --git a/crates/katana/primitives/src/utils/class.rs b/crates/katana/primitives/src/utils/class.rs index c97ae06a83..de2d83e10f 100644 --- a/crates/katana/primitives/src/utils/class.rs +++ b/crates/katana/primitives/src/utils/class.rs @@ -1,33 +1,39 @@ use anyhow::Result; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass; +use serde_json::Value; -use crate::contract::{ - CompiledContractClass, CompiledContractClassV0, CompiledContractClassV1, SierraClass, +use crate::class::{ + CompiledClass, DeprecatedCompiledClass, SierraClass, SierraCompiledClass, SierraProgram, }; -/// Parse a [`str`] into a [`CompiledContractClass`]. -pub fn parse_compiled_class(class: &str) -> Result { - if let Ok(class) = parse_compiled_class_v1(class) { - Ok(CompiledContractClass::V1(class)) +pub fn parse_compiled_class(artifact: Value) -> Result { + if let Ok(class) = parse_compiled_class_v1(artifact.clone()) { + Ok(CompiledClass::Class(class)) } else { - Ok(CompiledContractClass::V0(parse_compiled_class_v0(class)?)) + Ok(CompiledClass::Deprecated(parse_deprecated_compiled_class(artifact)?)) } } -/// Parse a [`str`] into a [`CompiledContractClassV1`]. -pub fn parse_compiled_class_v1(class: &str) -> Result { - let class: ContractClass = serde_json::from_str(class)?; - let class = CasmContractClass::from_contract_class(class, true)?; - Ok(CompiledContractClassV1::try_from(class)?) -} +pub fn parse_compiled_class_v1(class: Value) -> Result { + let class: ContractClass = serde_json::from_value(class)?; -/// Parse a [`str`] into a [`CompiledContractClassV0`]. -pub fn parse_compiled_class_v0(class: &str) -> Result { - serde_json::from_str(class) + let program = class.extract_sierra_program()?; + let entry_points_by_type = class.entry_points_by_type.clone(); + let sierra = SierraProgram { program, entry_points_by_type }; + + let casm = CasmContractClass::from_contract_class(class, true)?; + + Ok(SierraCompiledClass { casm, sierra }) } /// Parse a [`str`] into a [`SierraClass`]. pub fn parse_sierra_class(class: &str) -> Result { serde_json::from_str(class) } + +pub fn parse_deprecated_compiled_class( + class: Value, +) -> Result { + serde_json::from_value(class) +} diff --git a/crates/katana/rpc/rpc-api/src/lib.rs b/crates/katana/rpc/rpc-api/src/lib.rs index 6f381ac7be..198766158b 100644 --- a/crates/katana/rpc/rpc-api/src/lib.rs +++ b/crates/katana/rpc/rpc-api/src/lib.rs @@ -1,5 +1,6 @@ pub mod dev; pub mod katana; +pub mod saya; pub mod starknet; pub mod torii; @@ -10,4 +11,5 @@ pub enum ApiKind { Katana, Torii, Dev, + Saya, } diff --git a/crates/katana/rpc/rpc-api/src/saya.rs b/crates/katana/rpc/rpc-api/src/saya.rs new file mode 100644 index 0000000000..fa9017250f --- /dev/null +++ b/crates/katana/rpc/rpc-api/src/saya.rs @@ -0,0 +1,20 @@ +use jsonrpsee::core::RpcResult; +use jsonrpsee::proc_macros::rpc; +use katana_rpc_types::transaction::{TransactionsExecutionsPage, TransactionsPageCursor}; + +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "saya"))] +#[cfg_attr(feature = "client", rpc(client, server, namespace = "saya"))] +pub trait SayaApi { + /// Fetches the transaction execution info for all the transactions in the + /// given block. + /// + /// # Arguments + /// + /// * `block_number` - The block number to get executions from. + /// * `chunk_size` - The maximum number of transaction execution that should be returned. + #[method(name = "getTransactionsExecutions")] + async fn get_transactions_executions( + &self, + cursor: TransactionsPageCursor, + ) -> RpcResult; +} diff --git a/crates/katana/rpc/rpc-types/Cargo.toml b/crates/katana/rpc/rpc-types/Cargo.toml index 4bff449aaa..42d70a4c43 100644 --- a/crates/katana/rpc/rpc-types/Cargo.toml +++ b/crates/katana/rpc/rpc-types/Cargo.toml @@ -8,6 +8,7 @@ version.workspace = true [dependencies] katana-core = { path = "../../core" } +katana-executor.workspace = true katana-primitives = { path = "../../primitives" } katana-provider = { path = "../../storage/provider" } diff --git a/crates/katana/rpc/rpc-types/src/account.rs b/crates/katana/rpc/rpc-types/src/account.rs index f7b9f3c333..d73eb48f3c 100644 --- a/crates/katana/rpc/rpc-types/src/account.rs +++ b/crates/katana/rpc/rpc-types/src/account.rs @@ -1,5 +1,6 @@ use ethers::types::U256; -use katana_primitives::contract::{ClassHash, ContractAddress}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::ContractAddress; use katana_primitives::genesis::allocation::GenesisAccountAlloc; use katana_primitives::FieldElement; use serde::{Deserialize, Serialize}; diff --git a/crates/katana/rpc/rpc-types/src/error/mod.rs b/crates/katana/rpc/rpc-types/src/error/mod.rs index 4ba97df32c..e935e90516 100644 --- a/crates/katana/rpc/rpc-types/src/error/mod.rs +++ b/crates/katana/rpc/rpc-types/src/error/mod.rs @@ -1,3 +1,4 @@ pub mod katana; +pub mod saya; pub mod starknet; pub mod torii; diff --git a/crates/katana/rpc/rpc-types/src/error/saya.rs b/crates/katana/rpc/rpc-types/src/error/saya.rs new file mode 100644 index 0000000000..b832c46361 --- /dev/null +++ b/crates/katana/rpc/rpc-types/src/error/saya.rs @@ -0,0 +1,53 @@ +use jsonrpsee::core::Error; +use jsonrpsee::types::error::CallError; +use jsonrpsee::types::ErrorObject; +use katana_core::sequencer_error::SequencerError; +use katana_provider::error::ProviderError; + +#[derive(Debug, thiserror::Error, Clone)] +#[repr(i32)] +pub enum SayaApiError { + #[error("Transaction index out of bounds")] + TransactionOutOfBounds, + #[error("Block not found")] + BlockNotFound, + #[error("Transaction not found")] + TransactionNotFound, + #[error("An unexpected error occured: {reason}")] + UnexpectedError { reason: String }, +} + +impl SayaApiError { + fn code(&self) -> i32 { + match self { + SayaApiError::TransactionOutOfBounds => 1, + SayaApiError::BlockNotFound => 24, + SayaApiError::TransactionNotFound => 25, + SayaApiError::UnexpectedError { .. } => 63, + } + } +} + +impl From for SayaApiError { + fn from(value: ProviderError) -> Self { + SayaApiError::UnexpectedError { reason: value.to_string() } + } +} + +impl From for SayaApiError { + fn from(value: SequencerError) -> Self { + match value { + SequencerError::BlockNotFound(_) => SayaApiError::BlockNotFound, + err => SayaApiError::UnexpectedError { reason: err.to_string() }, + } + } +} + +impl From for Error { + fn from(err: SayaApiError) -> Self { + let code = err.code(); + let message = err.to_string(); + let err = ErrorObject::owned(code, message, None::<()>); + Error::Call(CallError::Custom(err)) + } +} diff --git a/crates/katana/rpc/rpc-types/src/error/starknet.rs b/crates/katana/rpc/rpc-types/src/error/starknet.rs index 564f704bb3..c369bcdc86 100644 --- a/crates/katana/rpc/rpc-types/src/error/starknet.rs +++ b/crates/katana/rpc/rpc-types/src/error/starknet.rs @@ -33,6 +33,13 @@ pub enum StarknetApiError { InvalidContinuationToken, #[error("Contract error")] ContractError { revert_error: String }, + #[error("Transaction execution error")] + TransactionExecutionError { + /// The index of the first transaction failing in a sequence of given transactions. + transaction_index: usize, + /// The revert error with the execution trace up to the point of failure. + execution_error: String, + }, #[error("Invalid contract class")] InvalidContractClass, #[error("Class already declared")] @@ -70,7 +77,7 @@ pub enum StarknetApiError { } impl StarknetApiError { - fn code(&self) -> i32 { + pub fn code(&self) -> i32 { match self { StarknetApiError::FailedToReceiveTxn => 1, StarknetApiError::ContractNotFound => 20, @@ -86,6 +93,7 @@ impl StarknetApiError { StarknetApiError::TooManyKeysInFilter => 34, StarknetApiError::FailedToFetchPendingTransactions => 38, StarknetApiError::ContractError { .. } => 40, + StarknetApiError::TransactionExecutionError { .. } => 41, StarknetApiError::InvalidContractClass => 50, StarknetApiError::ClassAlreadyDeclared => 51, StarknetApiError::InvalidTransactionNonce => 52, @@ -140,12 +148,6 @@ impl From for Error { impl From for StarknetApiError { fn from(value: SequencerError) -> Self { match value { - SequencerError::TransactionExecution(e) => { - StarknetApiError::ContractError { revert_error: e.to_string() } - } - SequencerError::EntryPointExecution(e) => { - StarknetApiError::ContractError { revert_error: e.to_string() } - } SequencerError::BlockNotFound(_) => StarknetApiError::BlockNotFound, SequencerError::ContractNotFound(_) => StarknetApiError::ContractNotFound, err => StarknetApiError::UnexpectedError { reason: err.to_string() }, diff --git a/crates/katana/rpc/rpc-types/src/error/torii.rs b/crates/katana/rpc/rpc-types/src/error/torii.rs index 8beeb260c4..c37f24e067 100644 --- a/crates/katana/rpc/rpc-types/src/error/torii.rs +++ b/crates/katana/rpc/rpc-types/src/error/torii.rs @@ -3,8 +3,7 @@ use jsonrpsee::core::Error; use jsonrpsee::types::error::CallError; use jsonrpsee::types::ErrorObject; use katana_core::sequencer_error::SequencerError; -use katana_primitives::receipt::Receipt; -use katana_primitives::transaction::TxWithHash; +use katana_core::service::block_producer::TxWithOutcome; use katana_provider::error::ProviderError; use crate::transaction::TransactionsPageCursor; @@ -21,10 +20,7 @@ pub enum ToriiApiError { #[error("Transaction receipt not found")] TransactionReceiptNotFound, #[error("Transactions not ready")] - TransactionsNotReady { - rx: Receiver>, - cursor: TransactionsPageCursor, - }, + TransactionsNotReady { rx: Receiver>, cursor: TransactionsPageCursor }, #[error("Long poll expired")] ChannelDisconnected, #[error("An unexpected error occured: {reason}")] diff --git a/crates/katana/rpc/rpc-types/src/lib.rs b/crates/katana/rpc/rpc-types/src/lib.rs index 8258c387e1..7b230146a0 100644 --- a/crates/katana/rpc/rpc-types/src/lib.rs +++ b/crates/katana/rpc/rpc-types/src/lib.rs @@ -10,6 +10,7 @@ pub mod event; pub mod message; pub mod receipt; pub mod state_update; +pub mod trace; pub mod transaction; use std::ops::Deref; diff --git a/crates/katana/rpc/rpc-types/src/trace.rs b/crates/katana/rpc/rpc-types/src/trace.rs new file mode 100644 index 0000000000..3bea0d6edb --- /dev/null +++ b/crates/katana/rpc/rpc-types/src/trace.rs @@ -0,0 +1,74 @@ +use katana_primitives::trace::CallInfo; +use starknet::core::types::{ + CallType, EntryPointType, ExecutionResources, OrderedEvent, OrderedMessage, +}; + +pub struct FunctionInvocation(pub starknet::core::types::FunctionInvocation); + +impl From for FunctionInvocation { + fn from(info: CallInfo) -> Self { + let entry_point_type = match info.entry_point_type { + katana_primitives::trace::EntryPointType::External => EntryPointType::External, + katana_primitives::trace::EntryPointType::L1Handler => EntryPointType::L1Handler, + katana_primitives::trace::EntryPointType::Constructor => EntryPointType::Constructor, + }; + + let call_type = match info.call_type { + katana_primitives::trace::CallType::Call => CallType::Call, + katana_primitives::trace::CallType::Delegate => CallType::Delegate, + }; + + let calls = info.inner_calls.into_iter().map(|c| FunctionInvocation::from(c).0).collect(); + + let events = info + .events + .into_iter() + .map(|e| OrderedEvent { order: e.order, data: e.data, keys: e.keys }) + .collect(); + + let messages = info + .l2_to_l1_messages + .into_iter() + .map(|m| OrderedMessage { + order: m.order, + payload: m.payload, + to_address: m.to_address, + from_address: m.from_address.into(), + }) + .collect(); + + let vm_resources = info.execution_resources; + let get_vm_resource = |name: &str| vm_resources.builtin_instance_counter.get(name).copied(); + + // TODO: replace execution resources type in primitive CallInfo with an already defined + // `TxExecutionResources` + let execution_resources = ExecutionResources { + steps: vm_resources.n_steps, + memory_holes: Some(vm_resources.n_memory_holes), + range_check_builtin_applications: get_vm_resource("range_check_builtin"), + pedersen_builtin_applications: get_vm_resource("pedersen_builtin"), + poseidon_builtin_applications: get_vm_resource("poseidon_builtin"), + ec_op_builtin_applications: get_vm_resource("ec_op_builtin"), + ecdsa_builtin_applications: get_vm_resource("ecdsa_builtin"), + bitwise_builtin_applications: get_vm_resource("bitwise_builtin"), + keccak_builtin_applications: get_vm_resource("keccak_builtin"), + segment_arena_builtin: get_vm_resource("segment_arena_builtin"), + }; + + Self(starknet::core::types::FunctionInvocation { + calls, + events, + messages, + call_type, + entry_point_type, + execution_resources, + result: info.retdata, + calldata: info.calldata, + caller_address: info.caller_address.into(), + contract_address: info.contract_address.into(), + entry_point_selector: info.entry_point_selector, + // See + class_hash: info.class_hash.expect("Class hash mut be set after execution"), + }) + } +} diff --git a/crates/katana/rpc/rpc-types/src/transaction.rs b/crates/katana/rpc/rpc-types/src/transaction.rs index c48faf34b6..87ecfde28a 100644 --- a/crates/katana/rpc/rpc-types/src/transaction.rs +++ b/crates/katana/rpc/rpc-types/src/transaction.rs @@ -3,11 +3,13 @@ use std::sync::Arc; use anyhow::Result; use derive_more::Deref; use katana_primitives::chain::ChainId; -use katana_primitives::contract::{ClassHash, ContractAddress}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::ContractAddress; use katana_primitives::conversion::rpc::{ compiled_class_hash_from_flattened_sierra_class, flattened_sierra_to_compiled_class, - legacy_rpc_to_inner_compiled_class, + legacy_rpc_to_compiled_class, }; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{ DeclareTx, DeclareTxV1, DeclareTxV2, DeclareTxV3, DeclareTxWithClass, DeployAccountTx, DeployAccountTxV1, DeployAccountTxV3, InvokeTx, InvokeTxV1, InvokeTxV3, TxHash, TxWithHash, @@ -23,9 +25,11 @@ use starknet::core::utils::get_contract_address; use crate::receipt::MaybePendingTxReceipt; +pub const CHUNK_SIZE_DEFAULT: u64 = 100; + #[derive(Debug, Clone, Serialize, Deserialize, Deref)] #[serde(transparent)] -pub struct BroadcastedInvokeTx(BroadcastedInvokeTransaction); +pub struct BroadcastedInvokeTx(pub BroadcastedInvokeTransaction); impl BroadcastedInvokeTx { pub fn is_query(&self) -> bool { @@ -65,7 +69,7 @@ impl BroadcastedInvokeTx { #[derive(Debug, Clone, Serialize, Deserialize, Deref)] #[serde(transparent)] -pub struct BroadcastedDeclareTx(BroadcastedDeclareTransaction); +pub struct BroadcastedDeclareTx(pub BroadcastedDeclareTransaction); impl BroadcastedDeclareTx { /// Validates that the provided compiled class hash is computed correctly from the class @@ -93,7 +97,7 @@ impl BroadcastedDeclareTx { match self.0 { BroadcastedDeclareTransaction::V1(tx) => { let (class_hash, compiled_class) = - legacy_rpc_to_inner_compiled_class(&tx.contract_class)?; + legacy_rpc_to_compiled_class(&tx.contract_class)?; Ok(DeclareTxWithClass { compiled_class, @@ -167,7 +171,7 @@ impl BroadcastedDeclareTx { #[derive(Debug, Clone, Serialize, Deserialize, Deref)] #[serde(transparent)] -pub struct BroadcastedDeployAccountTx(BroadcastedDeployAccountTransaction); +pub struct BroadcastedDeployAccountTx(pub BroadcastedDeployAccountTransaction); impl BroadcastedDeployAccountTx { pub fn is_query(&self) -> bool { @@ -497,10 +501,17 @@ impl From for DeployAccountTx { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Copy)] pub struct TransactionsPageCursor { pub block_number: u64, pub transaction_index: u64, + pub chunk_size: u64, +} + +impl Default for TransactionsPageCursor { + fn default() -> Self { + Self { block_number: 0, transaction_index: 0, chunk_size: CHUNK_SIZE_DEFAULT } + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -508,3 +519,9 @@ pub struct TransactionsPage { pub transactions: Vec<(TxWithHash, MaybePendingTxReceipt)>, pub cursor: TransactionsPageCursor, } + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TransactionsExecutionsPage { + pub transactions_executions: Vec, + pub cursor: TransactionsPageCursor, +} diff --git a/crates/katana/rpc/rpc/src/dev.rs b/crates/katana/rpc/rpc/src/dev.rs index 5475bc5290..e90290c1c5 100644 --- a/crates/katana/rpc/rpc/src/dev.rs +++ b/crates/katana/rpc/rpc/src/dev.rs @@ -2,22 +2,23 @@ use std::sync::Arc; use jsonrpsee::core::{async_trait, Error}; use katana_core::sequencer::KatanaSequencer; +use katana_executor::ExecutorFactory; use katana_primitives::FieldElement; use katana_rpc_api::dev::DevApiServer; use katana_rpc_types::error::katana::KatanaApiError; -pub struct DevApi { - sequencer: Arc, +pub struct DevApi { + sequencer: Arc>, } -impl DevApi { - pub fn new(sequencer: Arc) -> Self { +impl DevApi { + pub fn new(sequencer: Arc>) -> Self { Self { sequencer } } } #[async_trait] -impl DevApiServer for DevApi { +impl DevApiServer for DevApi { async fn generate_block(&self) -> Result<(), Error> { self.sequencer.block_producer().force_mine(); Ok(()) diff --git a/crates/katana/rpc/rpc/src/katana.rs b/crates/katana/rpc/rpc/src/katana.rs index 3dffbfdef4..46e5f61c68 100644 --- a/crates/katana/rpc/rpc/src/katana.rs +++ b/crates/katana/rpc/rpc/src/katana.rs @@ -2,21 +2,22 @@ use std::sync::Arc; use jsonrpsee::core::{async_trait, Error}; use katana_core::sequencer::KatanaSequencer; +use katana_executor::ExecutorFactory; use katana_rpc_api::katana::KatanaApiServer; use katana_rpc_types::account::Account; -pub struct KatanaApi { - sequencer: Arc, +pub struct KatanaApi { + sequencer: Arc>, } -impl KatanaApi { - pub fn new(sequencer: Arc) -> Self { +impl KatanaApi { + pub fn new(sequencer: Arc>) -> Self { Self { sequencer } } } #[async_trait] -impl KatanaApiServer for KatanaApi { +impl KatanaApiServer for KatanaApi { async fn predeployed_accounts(&self) -> Result, Error> { Ok(self .sequencer diff --git a/crates/katana/rpc/rpc/src/lib.rs b/crates/katana/rpc/rpc/src/lib.rs index 2a536b8aa2..d5974b69d8 100644 --- a/crates/katana/rpc/rpc/src/lib.rs +++ b/crates/katana/rpc/rpc/src/lib.rs @@ -1,6 +1,7 @@ pub mod config; pub mod dev; pub mod katana; +pub mod saya; pub mod starknet; pub mod torii; @@ -18,8 +19,10 @@ use jsonrpsee::tracing::debug; use jsonrpsee::types::Params; use jsonrpsee::RpcModule; use katana_core::sequencer::KatanaSequencer; +use katana_executor::ExecutorFactory; use katana_rpc_api::dev::DevApiServer; use katana_rpc_api::katana::KatanaApiServer; +use katana_rpc_api::saya::SayaApiServer; use katana_rpc_api::starknet::StarknetApiServer; use katana_rpc_api::torii::ToriiApiServer; use katana_rpc_api::ApiKind; @@ -27,10 +30,14 @@ use tower_http::cors::{Any, CorsLayer}; use crate::dev::DevApi; use crate::katana::KatanaApi; +use crate::saya::SayaApi; use crate::starknet::StarknetApi; use crate::torii::ToriiApi; -pub async fn spawn(sequencer: Arc, config: ServerConfig) -> Result { +pub async fn spawn( + sequencer: Arc>, + config: ServerConfig, +) -> Result { let mut methods = RpcModule::new(()); methods.register_method("health", |_, _| Ok(serde_json::json!({ "health": true })))?; @@ -48,6 +55,9 @@ pub async fn spawn(sequencer: Arc, config: ServerConfig) -> Res ApiKind::Torii => { methods.merge(ToriiApi::new(sequencer.clone()).into_rpc())?; } + ApiKind::Saya => { + methods.merge(SayaApi::new(sequencer.clone()).into_rpc())?; + } } } diff --git a/crates/katana/rpc/rpc/src/saya.rs b/crates/katana/rpc/rpc/src/saya.rs new file mode 100644 index 0000000000..330fe3eac6 --- /dev/null +++ b/crates/katana/rpc/rpc/src/saya.rs @@ -0,0 +1,76 @@ +use std::sync::Arc; + +use jsonrpsee::core::{async_trait, RpcResult}; +use katana_core::sequencer::KatanaSequencer; +use katana_executor::ExecutorFactory; +use katana_primitives::block::BlockHashOrNumber; +use katana_provider::traits::transaction::TransactionTraceProvider; +use katana_rpc_api::saya::SayaApiServer; +use katana_rpc_types::error::saya::SayaApiError; +use katana_rpc_types::transaction::{TransactionsExecutionsPage, TransactionsPageCursor}; +use katana_tasks::TokioTaskSpawner; + +pub struct SayaApi { + sequencer: Arc>, +} + +impl Clone for SayaApi { + fn clone(&self) -> Self { + Self { sequencer: self.sequencer.clone() } + } +} + +impl SayaApi { + pub fn new(sequencer: Arc>) -> Self { + Self { sequencer } + } + + async fn on_io_blocking_task(&self, func: F) -> T + where + F: FnOnce(Self) -> T + Send + 'static, + T: Send + 'static, + { + let this = self.clone(); + TokioTaskSpawner::new().unwrap().spawn_blocking(move || func(this)).await.unwrap() + } +} + +#[async_trait] +impl SayaApiServer for SayaApi { + async fn get_transactions_executions( + &self, + cursor: TransactionsPageCursor, + ) -> RpcResult { + self.on_io_blocking_task(move |this| { + let provider = this.sequencer.backend.blockchain.provider(); + let mut next_cursor = cursor; + + let transactions_executions = provider + .transactions_executions_by_block(BlockHashOrNumber::Num(cursor.block_number)) + .map_err(SayaApiError::from)? + .ok_or(SayaApiError::BlockNotFound)?; + + let total_execs = transactions_executions.len() as u64; + + let transactions_executions = transactions_executions + .into_iter() + .skip(cursor.transaction_index as usize) + .take(cursor.chunk_size as usize) + .collect::>(); + + if cursor.transaction_index + cursor.chunk_size >= total_execs { + // All transactions of the block pointed by the cursor were fetched. + // Indicate to the client this situation by setting the block number + // to the next block and transaction index to 0. + next_cursor.block_number = cursor.block_number + 1; + next_cursor.transaction_index = 0; + } else { + next_cursor.transaction_index += + cursor.transaction_index + transactions_executions.len() as u64; + } + + Ok(TransactionsExecutionsPage { transactions_executions, cursor: next_cursor }) + }) + .await + } +} diff --git a/crates/katana/rpc/rpc/src/starknet.rs b/crates/katana/rpc/rpc/src/starknet.rs index f9bedb9926..a02ed30c48 100644 --- a/crates/katana/rpc/rpc/src/starknet.rs +++ b/crates/katana/rpc/rpc/src/starknet.rs @@ -3,9 +3,10 @@ use std::sync::Arc; use jsonrpsee::core::{async_trait, Error, RpcResult}; use katana_core::backend::contract::StarknetContract; use katana_core::sequencer::KatanaSequencer; -use katana_executor::blockifier::utils::EntryPointCall; +use katana_executor::{EntryPointCall, ExecutionResult, ExecutorFactory, ResultAndStates}; use katana_primitives::block::{BlockHashOrNumber, BlockIdOrTag, FinalityStatus, PartialHeader}; use katana_primitives::conversion::rpc::legacy_inner_to_rpc_class; +use katana_primitives::receipt::Receipt; use katana_primitives::transaction::{ExecutableTx, ExecutableTxWithHash, TxHash}; use katana_primitives::version::CURRENT_STARKNET_VERSION; use katana_primitives::FieldElement; @@ -23,6 +24,7 @@ use katana_rpc_types::event::{EventFilterWithPage, EventsPage}; use katana_rpc_types::message::MsgFromL1; use katana_rpc_types::receipt::{MaybePendingTxReceipt, PendingTxReceipt}; use katana_rpc_types::state_update::StateUpdate; +use katana_rpc_types::trace::FunctionInvocation; use katana_rpc_types::transaction::{ BroadcastedDeclareTx, BroadcastedDeployAccountTx, BroadcastedInvokeTx, BroadcastedTx, DeclareTxResult, DeployAccountTxResult, InvokeTxResult, Tx, @@ -34,21 +36,28 @@ use katana_rpc_types::{ use katana_rpc_types_builder::ReceiptBuilder; use katana_tasks::{BlockingTaskPool, TokioTaskSpawner}; use starknet::core::types::{ - BlockTag, SimulatedTransaction, TransactionExecutionStatus, TransactionStatus, + BlockTag, DeclareTransactionTrace, DeployAccountTransactionTrace, ExecuteInvocation, + InvokeTransactionTrace, L1HandlerTransactionTrace, RevertedInvocation, SimulatedTransaction, + TransactionExecutionStatus, TransactionStatus, TransactionTrace, }; -#[derive(Clone)] -pub struct StarknetApi { - inner: Arc, +pub struct StarknetApi { + inner: Arc>, } -struct StarknetApiInner { - sequencer: Arc, +impl Clone for StarknetApi { + fn clone(&self) -> Self { + Self { inner: Arc::clone(&self.inner) } + } +} + +struct StarknetApiInner { + sequencer: Arc>, blocking_task_pool: BlockingTaskPool, } -impl StarknetApi { - pub fn new(sequencer: Arc) -> Self { +impl StarknetApi { + pub fn new(sequencer: Arc>) -> Self { let blocking_task_pool = BlockingTaskPool::new().expect("failed to create blocking task pool"); Self { inner: Arc::new(StarknetApiInner { sequencer, blocking_task_pool }) } @@ -71,9 +80,50 @@ impl StarknetApi { let this = self.clone(); TokioTaskSpawner::new().unwrap().spawn_blocking(move || func(this)).await.unwrap() } + + fn estimate_fee_with( + &self, + transactions: Vec, + block_id: BlockIdOrTag, + flags: katana_executor::SimulationFlag, + ) -> Result, StarknetApiError> { + let sequencer = &self.inner.sequencer; + // get the state and block env at the specified block for execution + let state = sequencer.state(&block_id).map_err(StarknetApiError::from)?; + let env = sequencer + .block_env_at(block_id) + .map_err(StarknetApiError::from)? + .ok_or(StarknetApiError::BlockNotFound)?; + + // create the executor + let executor = sequencer.backend.executor_factory.with_state_and_block_env(state, env); + let results = executor.estimate_fee(transactions, flags); + + let mut estimates = Vec::with_capacity(results.len()); + for (i, res) in results.into_iter().enumerate() { + match res { + Ok(fee) => estimates.push(FeeEstimate { + gas_price: fee.gas_price.into(), + gas_consumed: fee.gas_consumed.into(), + overall_fee: fee.overall_fee.into(), + unit: fee.unit, + }), + + Err(err) => { + return Err(StarknetApiError::TransactionExecutionError { + transaction_index: i, + execution_error: err.to_string(), + }); + } + } + } + + Ok(estimates) + } } + #[async_trait] -impl StarknetApiServer for StarknetApi { +impl StarknetApiServer for StarknetApi { async fn chain_id(&self) -> RpcResult { Ok(FieldElement::from(self.inner.sequencer.chain_id()).into()) } @@ -163,24 +213,24 @@ impl StarknetApiServer for StarknetApi { let provider = this.inner.sequencer.backend.blockchain.provider(); if BlockIdOrTag::Tag(BlockTag::Pending) == block_id { - if let Some(pending_state) = this.inner.sequencer.pending_state() { - let block_env = pending_state.block_envs.read().0.clone(); - let latest_hash = - BlockHashProvider::latest_hash(provider).map_err(StarknetApiError::from)?; + if let Some(executor) = this.inner.sequencer.pending_executor() { + let block_env = executor.read().block_env(); + let latest_hash = provider.latest_hash().map_err(StarknetApiError::from)?; let gas_prices = block_env.l1_gas_prices.clone(); let header = PartialHeader { + number: block_env.number, gas_prices, parent_hash: latest_hash, - version: CURRENT_STARKNET_VERSION, timestamp: block_env.timestamp, + version: CURRENT_STARKNET_VERSION, sequencer_address: block_env.sequencer_address, }; - let transactions = pending_state - .executed_txs + let transactions = executor .read() + .transactions() .iter() .map(|(tx, _)| tx.hash) .collect::>(); @@ -213,12 +263,13 @@ impl StarknetApiServer for StarknetApi { self.on_io_blocking_task(move |this| { // TEMP: have to handle pending tag independently for now let tx = if BlockIdOrTag::Tag(BlockTag::Pending) == block_id { - let Some(pending_state) = this.inner.sequencer.pending_state() else { + let Some(executor) = this.inner.sequencer.pending_executor() else { return Err(StarknetApiError::BlockNotFound.into()); }; - let pending_txs = pending_state.executed_txs.read(); - pending_txs.iter().nth(index as usize).map(|(tx, _)| tx.clone()) + let executor = executor.read(); + let pending_txs = executor.transactions(); + pending_txs.get(index as usize).map(|(tx, _)| tx.clone()) } else { let provider = &this.inner.sequencer.backend.blockchain.provider(); @@ -241,14 +292,14 @@ impl StarknetApiServer for StarknetApi { let provider = this.inner.sequencer.backend.blockchain.provider(); if BlockIdOrTag::Tag(BlockTag::Pending) == block_id { - if let Some(pending_state) = this.inner.sequencer.pending_state() { - let block_env = pending_state.block_envs.read().0.clone(); - let latest_hash = - BlockHashProvider::latest_hash(provider).map_err(StarknetApiError::from)?; + if let Some(executor) = this.inner.sequencer.pending_executor() { + let block_env = executor.read().block_env(); + let latest_hash = provider.latest_hash().map_err(StarknetApiError::from)?; let gas_prices = block_env.l1_gas_prices.clone(); let header = PartialHeader { + number: block_env.number, gas_prices, parent_hash: latest_hash, version: CURRENT_STARKNET_VERSION, @@ -256,9 +307,9 @@ impl StarknetApiServer for StarknetApi { sequencer_address: block_env.sequencer_address, }; - let transactions = pending_state - .executed_txs + let transactions = executor .read() + .transactions() .iter() .map(|(tx, _)| tx.clone()) .collect::>(); @@ -323,17 +374,23 @@ impl StarknetApiServer for StarknetApi { Some(receipt) => Ok(MaybePendingTxReceipt::Receipt(receipt)), None => { - let pending_receipt = this.inner.sequencer.pending_state().and_then(|s| { - s.executed_txs - .read() - .iter() - .find(|(tx, _)| tx.hash == transaction_hash) - .map(|(_, rct)| rct.receipt.clone()) - }); - - let Some(pending_receipt) = pending_receipt else { - return Err(StarknetApiError::TxnHashNotFound.into()); - }; + let executor = this.inner.sequencer.pending_executor(); + let pending_receipt = executor + .and_then(|executor| { + executor.read().transactions().iter().find_map(|(tx, res)| { + if tx.hash == transaction_hash { + match res { + ExecutionResult::Failed { .. } => None, + ExecutionResult::Success { receipt, .. } => { + Some(receipt.clone()) + } + } + } else { + None + } + }) + }) + .ok_or(Error::from(StarknetApiError::TxnHashNotFound))?; Ok(MaybePendingTxReceipt::Pending(PendingTxReceipt::new( transaction_hash, @@ -423,9 +480,23 @@ impl StarknetApiServer for StarknetApi { entry_point_selector: request.entry_point_selector, }; - let res = - this.inner.sequencer.call(request, block_id).map_err(StarknetApiError::from)?; - Ok(res.into_iter().map(|v| v.into()).collect()) + let sequencer = &this.inner.sequencer; + + // get the state and block env at the specified block for function call execution + let state = sequencer.state(&block_id).map_err(StarknetApiError::from)?; + let env = sequencer + .block_env_at(block_id) + .map_err(StarknetApiError::from)? + .ok_or(StarknetApiError::BlockNotFound)?; + + let executor = sequencer.backend.executor_factory.with_state_and_block_env(state, env); + + match executor.call(request) { + Ok(retdata) => Ok(retdata.into_iter().map(|v| v.into()).collect()), + Err(err) => Err(Error::from(StarknetApiError::ContractError { + revert_error: err.to_string(), + })), + } }) .await } @@ -479,7 +550,8 @@ impl StarknetApiServer for StarknetApi { block_id: BlockIdOrTag, ) -> RpcResult> { self.on_cpu_blocking_task(move |this| { - let chain_id = this.inner.sequencer.chain_id(); + let sequencer = &this.inner.sequencer; + let chain_id = sequencer.chain_id(); let transactions = request .into_iter() @@ -513,17 +585,20 @@ impl StarknetApiServer for StarknetApi { }) .collect::, _>>()?; - let skip_validate = simulation_flags - .iter() - .any(|flag| flag == &SimulationFlagForEstimateFee::SkipValidate); + let skip_validate = + simulation_flags.contains(&SimulationFlagForEstimateFee::SkipValidate); - let res = this - .inner - .sequencer - .estimate_fee(transactions, block_id, skip_validate) - .map_err(StarknetApiError::from)?; + // If the node is run with transaction validation disabled, then we should not validate + // transactions when estimating the fee even if the `SKIP_VALIDATE` flag is not set. + let should_validate = + !(skip_validate || this.inner.sequencer.backend.config.disable_validate); + let flags = katana_executor::SimulationFlag { + skip_validate: !should_validate, + ..Default::default() + }; - Ok(res) + let results = this.estimate_fee_with(transactions, block_id, flags)?; + Ok(results) }) .await } @@ -538,17 +613,25 @@ impl StarknetApiServer for StarknetApi { let tx = message.into_tx_with_chain_id(chain_id); let hash = tx.calculate_hash(); - let tx: ExecutableTxWithHash = ExecutableTxWithHash { hash, transaction: tx.into() }; - let res = this - .inner - .sequencer - .estimate_fee(vec![tx], block_id, false) - .map_err(StarknetApiError::from)? - .pop() - .expect("should have estimate result"); + let result = this.estimate_fee_with( + vec![ExecutableTxWithHash { hash, transaction: tx.into() }], + block_id, + Default::default(), + ); + match result { + Ok(mut res) => { + if let Some(fee) = res.pop() { + Ok(fee) + } else { + Err(Error::from(StarknetApiError::UnexpectedError { + reason: "Fee estimation result should exist".into(), + })) + } + } - Ok(res) + Err(err) => Err(Error::from(err)), + } }) .await } @@ -639,33 +722,26 @@ impl StarknetApiServer for StarknetApi { } } - let pending_state = this.inner.sequencer.pending_state(); - let state = pending_state.ok_or(StarknetApiError::TxnHashNotFound)?; - let executed_txs = state.executed_txs.read(); - - // attemps to find in the valid transactions list first (executed_txs) - // if not found, then search in the rejected transactions list (rejected_txs) - if let Some(is_reverted) = executed_txs - .iter() - .find(|(tx, _)| tx.hash == transaction_hash) - .map(|(_, rct)| rct.receipt.is_reverted()) - { - let exec_status = if is_reverted { - TransactionExecutionStatus::Reverted - } else { - TransactionExecutionStatus::Succeeded - }; - - Ok(TransactionStatus::AcceptedOnL2(exec_status)) - } else { - let rejected_txs = state.rejected_txs.read(); + let pending_executor = + this.inner.sequencer.pending_executor().ok_or(StarknetApiError::TxnHashNotFound)?; + let pending_executor = pending_executor.read(); + + let pending_txs = pending_executor.transactions(); + let status = + pending_txs.iter().find(|(tx, _)| tx.hash == transaction_hash).map(|(_, res)| { + match res { + ExecutionResult::Failed { .. } => TransactionStatus::Rejected, + ExecutionResult::Success { receipt, .. } => { + TransactionStatus::AcceptedOnL2(if receipt.is_reverted() { + TransactionExecutionStatus::Reverted + } else { + TransactionExecutionStatus::Succeeded + }) + } + } + }); - rejected_txs - .iter() - .find(|(tx, _)| tx.hash == transaction_hash) - .map(|_| TransactionStatus::Rejected) - .ok_or(Error::from(StarknetApiError::TxnHashNotFound)) - } + status.ok_or(Error::from(StarknetApiError::TxnHashNotFound)) }) .await } @@ -677,9 +753,8 @@ impl StarknetApiServer for StarknetApi { simulation_flags: Vec, ) -> RpcResult> { self.on_cpu_blocking_task(move |this| { - let charge_fee = !simulation_flags.contains(&SimulationFlag::SkipFeeCharge); - let validate = !simulation_flags.contains(&SimulationFlag::SkipValidate); let chain_id = this.inner.sequencer.chain_id(); + let executables = transactions .into_iter() .map(|tx| { @@ -713,13 +788,114 @@ impl StarknetApiServer for StarknetApi { }) .collect::, _>>()?; - let res = this - .inner - .sequencer - .simulate_transactions(executables, block_id, validate, charge_fee) - .map_err(StarknetApiError::from)?; + // If the node is run with transaction validation disabled, then we should not validate + // even if the `SKIP_VALIDATE` flag is not set. + let should_validate = !(simulation_flags.contains(&SimulationFlag::SkipValidate) + || this.inner.sequencer.backend.config.disable_validate); + // If the node is run with fee charge disabled, then we should disable charing fees even + // if the `SKIP_FEE_CHARGE` flag is not set. + let should_skip_fee = !(simulation_flags.contains(&SimulationFlag::SkipFeeCharge) + || this.inner.sequencer.backend.config.disable_fee); + + let flags = katana_executor::SimulationFlag { + skip_validate: !should_validate, + skip_fee_transfer: !should_skip_fee, + ..Default::default() + }; + + let sequencer = &this.inner.sequencer; + // get the state and block env at the specified block for execution + let state = sequencer.state(&block_id).map_err(StarknetApiError::from)?; + let env = sequencer + .block_env_at(block_id) + .map_err(StarknetApiError::from)? + .ok_or(StarknetApiError::BlockNotFound)?; + + // create the executor + let executor = sequencer.backend.executor_factory.with_state_and_block_env(state, env); + let results = executor.simulate(executables, flags); + + let mut simulated = Vec::with_capacity(results.len()); + for (i, ResultAndStates { result, .. }) in results.into_iter().enumerate() { + match result { + ExecutionResult::Success { trace, fee, receipt } => { + let fee_transfer_invocation = + trace.fee_transfer_call_info.map(|f| FunctionInvocation::from(f).0); + let validate_invocation = + trace.validate_call_info.map(|f| FunctionInvocation::from(f).0); + let execute_invocation = + trace.execute_call_info.map(|f| FunctionInvocation::from(f).0); + let revert_reason = trace.revert_error; + // TODO: compute the state diff + let state_diff = None; + + let transaction_trace = match receipt { + Receipt::Invoke(_) => { + TransactionTrace::Invoke(InvokeTransactionTrace { + fee_transfer_invocation, + validate_invocation, + state_diff, + execute_invocation: if let Some(revert_reason) = revert_reason { + ExecuteInvocation::Reverted(RevertedInvocation { + revert_reason, + }) + } else { + ExecuteInvocation::Success( + execute_invocation + .expect("should exist if not reverted"), + ) + }, + }) + } + + Receipt::Declare(_) => { + TransactionTrace::Declare(DeclareTransactionTrace { + fee_transfer_invocation, + validate_invocation, + state_diff, + }) + } + + Receipt::DeployAccount(_) => { + TransactionTrace::DeployAccount(DeployAccountTransactionTrace { + fee_transfer_invocation, + validate_invocation, + state_diff, + constructor_invocation: execute_invocation + .expect("should exist bcs tx succeed"), + }) + } + + Receipt::L1Handler(_) => { + TransactionTrace::L1Handler(L1HandlerTransactionTrace { + state_diff, + function_invocation: execute_invocation + .expect("should exist bcs tx succeed"), + }) + } + }; + + simulated.push(SimulatedTransaction { + transaction_trace, + fee_estimation: FeeEstimate { + unit: fee.unit, + gas_price: fee.gas_price.into(), + overall_fee: fee.overall_fee.into(), + gas_consumed: fee.gas_consumed.into(), + }, + }) + } + + ExecutionResult::Failed { error } => { + return Err(Error::from(StarknetApiError::TransactionExecutionError { + transaction_index: i, + execution_error: error.to_string(), + })); + } + } + } - Ok(res) + Ok(simulated) }) .await } diff --git a/crates/katana/rpc/rpc/src/torii.rs b/crates/katana/rpc/rpc/src/torii.rs index a3a253f4af..d80baf35b6 100644 --- a/crates/katana/rpc/rpc/src/torii.rs +++ b/crates/katana/rpc/rpc/src/torii.rs @@ -4,6 +4,7 @@ use futures::StreamExt; use jsonrpsee::core::{async_trait, RpcResult}; use katana_core::sequencer::KatanaSequencer; use katana_core::service::block_producer::BlockProducerMode; +use katana_executor::ExecutorFactory; use katana_primitives::block::BlockHashOrNumber; use katana_provider::traits::transaction::TransactionProvider; use katana_rpc_api::torii::ToriiApiServer; @@ -15,13 +16,18 @@ use katana_tasks::TokioTaskSpawner; const MAX_PAGE_SIZE: usize = 100; -#[derive(Clone)] -pub struct ToriiApi { - sequencer: Arc, +pub struct ToriiApi { + sequencer: Arc>, } -impl ToriiApi { - pub fn new(sequencer: Arc) -> Self { +impl Clone for ToriiApi { + fn clone(&self) -> Self { + Self { sequencer: self.sequencer.clone() } + } +} + +impl ToriiApi { + pub fn new(sequencer: Arc>) -> Self { Self { sequencer } } @@ -36,7 +42,7 @@ impl ToriiApi { } #[async_trait] -impl ToriiApiServer for ToriiApi { +impl ToriiApiServer for ToriiApi { async fn get_transactions( &self, cursor: TransactionsPageCursor, @@ -44,7 +50,7 @@ impl ToriiApiServer for ToriiApi { match self .on_io_blocking_task(move |this| { let mut transactions = Vec::new(); - let mut next_cursor = cursor.clone(); + let mut next_cursor = cursor; let provider = this.sequencer.backend.blockchain.provider(); let latest_block_number = @@ -93,25 +99,27 @@ impl ToriiApiServer for ToriiApi { } } - if let Some(pending_state) = this.sequencer.pending_state() { + if let Some(pending_executor) = this.sequencer.pending_executor() { let remaining = MAX_PAGE_SIZE - transactions.len(); // If cursor is in the pending block if cursor.block_number == latest_block_number + 1 { - let pending_transactions = pending_state - .executed_txs + let pending_transactions = pending_executor .read() + .transactions() .iter() .skip(cursor.transaction_index as usize) .take(remaining) - .map(|(tx, info)| { - ( - tx.clone(), - MaybePendingTxReceipt::Pending(PendingTxReceipt::new( - tx.hash, - info.receipt.clone(), - )), - ) + .filter_map(|(tx, res)| { + res.receipt().map(|rct| { + ( + tx.clone(), + MaybePendingTxReceipt::Pending(PendingTxReceipt::new( + tx.hash, + rct.clone(), + )), + ) + }) }) .collect::>(); @@ -135,19 +143,21 @@ impl ToriiApiServer for ToriiApi { next_cursor.transaction_index += pending_transactions.len() as u64; transactions.extend(pending_transactions); } else { - let pending_transactions = pending_state - .executed_txs + let pending_transactions = pending_executor .read() + .transactions() .iter() .take(remaining) - .map(|(tx, info)| { - ( - tx.clone(), - MaybePendingTxReceipt::Pending(PendingTxReceipt::new( - tx.hash, - info.receipt.clone(), - )), - ) + .filter_map(|(tx, res)| { + res.receipt().map(|rct| { + ( + tx.clone(), + MaybePendingTxReceipt::Pending(PendingTxReceipt::new( + tx.hash, + rct.clone(), + )), + ) + }) }) .collect::>(); next_cursor.block_number += 1; @@ -188,11 +198,12 @@ impl ToriiApiServer for ToriiApi { .await .ok_or(ToriiApiError::ChannelDisconnected)? .into_iter() - .map(|(tx, receipt)| { + .map(|tx_outcome| { ( - tx.clone(), + tx_outcome.tx.clone(), MaybePendingTxReceipt::Pending(PendingTxReceipt::new( - tx.hash, receipt, + tx_outcome.tx.hash, + tx_outcome.receipt, )), ) }) diff --git a/crates/katana/rpc/rpc/tests/common/mod.rs b/crates/katana/rpc/rpc/tests/common/mod.rs index 1d214569b5..321cb8b0ee 100644 --- a/crates/katana/rpc/rpc/tests/common/mod.rs +++ b/crates/katana/rpc/rpc/tests/common/mod.rs @@ -5,8 +5,10 @@ use anyhow::{anyhow, Result}; use cairo_lang_starknet::casm_contract_class::CasmContractClass; use cairo_lang_starknet::contract_class::ContractClass; use katana_primitives::conversion::rpc::CompiledClass; +use starknet::accounts::Call; use starknet::core::types::contract::SierraClass; use starknet::core::types::{FieldElement, FlattenedSierraClass}; +use starknet::core::utils::get_selector_from_name; pub fn prepare_contract_declaration_params( artifact_path: &PathBuf, @@ -33,3 +35,31 @@ fn get_compiled_class_hash(artifact_path: &PathBuf) -> Result { let compiled_class: CompiledClass = serde_json::from_str(&res)?; Ok(compiled_class.class_hash()?) } + +// TODO: not sure why this function is not seen as used +// as prepare_contract_declaration_params is. +#[allow(dead_code)] +pub fn build_deploy_cairo1_contract_call(class_hash: FieldElement, salt: FieldElement) -> Call { + let constructor_calldata = vec![FieldElement::from(1_u32), FieldElement::from(2_u32)]; + + let calldata = [ + vec![ + class_hash, // class hash + salt, // salt + FieldElement::ZERO, // unique + FieldElement::from(constructor_calldata.len()), // constructor calldata len + ], + constructor_calldata.clone(), + ] + .concat(); + + Call { + calldata, + // devnet UDC address + to: FieldElement::from_hex_be( + "0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf", + ) + .unwrap(), + selector: get_selector_from_name("deployContract").unwrap(), + } +} diff --git a/crates/katana/rpc/rpc/tests/saya.rs b/crates/katana/rpc/rpc/tests/saya.rs new file mode 100644 index 0000000000..dd1135c4b2 --- /dev/null +++ b/crates/katana/rpc/rpc/tests/saya.rs @@ -0,0 +1,186 @@ +use std::path::PathBuf; +use std::sync::Arc; +use std::time::Duration; + +use dojo_test_utils::sequencer::{get_default_test_starknet_config, TestSequencer}; +use jsonrpsee::http_client::HttpClientBuilder; +use katana_core::sequencer::SequencerConfig; +use katana_rpc_api::dev::DevApiClient; +use katana_rpc_api::saya::SayaApiClient; +use katana_rpc_api::starknet::StarknetApiClient; +use katana_rpc_types::transaction::{ + TransactionsExecutionsPage, TransactionsPageCursor, CHUNK_SIZE_DEFAULT, +}; +use starknet::accounts::Account; +use starknet::core::types::{FieldElement, TransactionStatus}; +use tokio::time::sleep; + +pub const ENOUGH_GAS: &str = "0x100000000000000000"; + +mod common; + +#[tokio::test(flavor = "multi_thread")] +async fn no_pending_support() { + // Saya does not support the pending block and only work on sealed blocks. + let sequencer = TestSequencer::start( + SequencerConfig { block_time: None, no_mining: true, ..Default::default() }, + get_default_test_starknet_config(), + ) + .await; + + let client = HttpClientBuilder::default().build(sequencer.url()).unwrap(); + + // Should return block not found on trying to fetch the pending block. + let cursor = TransactionsPageCursor { block_number: 1, ..Default::default() }; + + match client.get_transactions_executions(cursor).await { + Ok(_) => panic!("Expected error BlockNotFound"), + Err(e) => { + let eo: jsonrpsee::types::ErrorObject<'_> = e.into(); + assert_eq!(eo.code(), 24); + assert_eq!(eo.message(), "Block not found"); + } + }; +} + +#[tokio::test(flavor = "multi_thread")] +async fn process_sealed_block_only() { + // Saya does not support the pending block and only work on sealed blocks. + let sequencer = TestSequencer::start( + SequencerConfig { block_time: None, no_mining: true, ..Default::default() }, + get_default_test_starknet_config(), + ) + .await; + + let client = HttpClientBuilder::default().build(sequencer.url()).unwrap(); + + let account = sequencer.account(); + + let path: PathBuf = PathBuf::from("tests/test_data/cairo1_contract.json"); + let (contract, compiled_class_hash) = + common::prepare_contract_declaration_params(&path).unwrap(); + let contract = Arc::new(contract); + + // Should return successfully when no transactions have been mined on a block. + let mut cursor = TransactionsPageCursor::default(); + + let response: TransactionsExecutionsPage = + client.get_transactions_executions(cursor).await.unwrap(); + + assert!(response.transactions_executions.is_empty()); + assert!(response.cursor.block_number == 1); + assert!(response.cursor.transaction_index == 0); + assert!(response.cursor.chunk_size == CHUNK_SIZE_DEFAULT); + + let _declare_res = account.declare(contract.clone(), compiled_class_hash).send().await.unwrap(); + + // Should still return 0 transactions execution for the block 0. + let response: TransactionsExecutionsPage = + client.get_transactions_executions(cursor).await.unwrap(); + + assert!(response.transactions_executions.is_empty()); + assert!(response.cursor.block_number == 1); + assert!(response.cursor.transaction_index == 0); + assert!(response.cursor.chunk_size == CHUNK_SIZE_DEFAULT); + + // Create block 1. + let _: () = client.generate_block().await.unwrap(); + + // Should now return 1 transaction from the mined block. + cursor.block_number = 1; + let response: TransactionsExecutionsPage = + client.get_transactions_executions(cursor).await.unwrap(); + + assert!(response.transactions_executions.len() == 1); + assert!(response.cursor.block_number == 2); + assert!(response.cursor.transaction_index == 0); + assert!(response.cursor.chunk_size == CHUNK_SIZE_DEFAULT); +} + +#[tokio::test(flavor = "multi_thread")] +async fn executions_chunks_logic_ok() { + let sequencer = TestSequencer::start( + SequencerConfig { block_time: None, no_mining: true, ..Default::default() }, + get_default_test_starknet_config(), + ) + .await; + + let client = HttpClientBuilder::default().build(sequencer.url()).unwrap(); + + let account = sequencer.account(); + + let path: PathBuf = PathBuf::from("tests/test_data/cairo1_contract.json"); + let (contract, compiled_class_hash) = + common::prepare_contract_declaration_params(&path).unwrap(); + let contract = Arc::new(contract); + + let declare_res = account.declare(contract.clone(), compiled_class_hash).send().await.unwrap(); + + let max_fee = FieldElement::from_hex_be(ENOUGH_GAS).unwrap(); + let mut nonce = FieldElement::ONE; + let mut last_tx_hash = FieldElement::ZERO; + + // Prepare 29 transactions to test chunks (30 at total with the previous declare). + for i in 0..29 { + let deploy_call = + common::build_deploy_cairo1_contract_call(declare_res.class_hash, (i + 2_u32).into()); + let deploy_txn = account.execute(vec![deploy_call]).nonce(nonce).max_fee(max_fee); + let tx_hash = deploy_txn.send().await.unwrap().transaction_hash; + nonce += FieldElement::ONE; + + if i == 28 { + last_tx_hash = tx_hash; + } + } + + assert!(last_tx_hash != FieldElement::ZERO); + + // Poll the statux of the last tx sent. + let max_retry = 10; + let mut attempt = 0; + loop { + match client.transaction_status(last_tx_hash).await { + Ok(s) => { + if s != TransactionStatus::Received { + break; + } + } + Err(_) => { + assert!(attempt < max_retry); + sleep(Duration::from_millis(300)).await; + attempt += 1; + } + } + } + + // Create block 1. + let _: () = client.generate_block().await.unwrap(); + + let cursor = TransactionsPageCursor { block_number: 1, chunk_size: 15, ..Default::default() }; + + let response: TransactionsExecutionsPage = + client.get_transactions_executions(cursor).await.unwrap(); + assert!(response.transactions_executions.len() == 15); + assert!(response.cursor.block_number == 1); + assert!(response.cursor.transaction_index == 15); + + // Should get the remaining 15 transactions and cursor to the next block. + let response: TransactionsExecutionsPage = + client.get_transactions_executions(response.cursor).await.unwrap(); + + assert!(response.transactions_executions.len() == 15); + assert!(response.cursor.block_number == 2); + assert!(response.cursor.transaction_index == 0); + + // Create block 2. + let _: () = client.generate_block().await.unwrap(); + + let response: TransactionsExecutionsPage = + client.get_transactions_executions(response.cursor).await.unwrap(); + + assert!(response.transactions_executions.is_empty()); + assert!(response.cursor.block_number == 3); + assert!(response.cursor.transaction_index == 0); + + sequencer.stop().expect("failed to stop sequencer"); +} diff --git a/crates/katana/rpc/rpc/tests/starknet.rs b/crates/katana/rpc/rpc/tests/starknet.rs index 9daff5b2fa..ec0bf3a57f 100644 --- a/crates/katana/rpc/rpc/tests/starknet.rs +++ b/crates/katana/rpc/rpc/tests/starknet.rs @@ -14,8 +14,6 @@ use starknet::core::types::{ use starknet::core::utils::{get_contract_address, get_selector_from_name}; use starknet::providers::Provider; -use crate::common::prepare_contract_declaration_params; - mod common; const WAIT_TX_DELAY_MILLIS: u64 = 1000; @@ -27,7 +25,8 @@ async fn test_send_declare_and_deploy_contract() { let account = sequencer.account(); let path: PathBuf = PathBuf::from("tests/test_data/cairo1_contract.json"); - let (contract, compiled_class_hash) = prepare_contract_declaration_params(&path).unwrap(); + let (contract, compiled_class_hash) = + common::prepare_contract_declaration_params(&path).unwrap(); let class_hash = contract.class_hash(); let res = account.declare(Arc::new(contract), compiled_class_hash).send().await.unwrap(); diff --git a/crates/katana/rpc/rpc/tests/torii.rs b/crates/katana/rpc/rpc/tests/torii.rs index 05781323b3..5ac772815f 100644 --- a/crates/katana/rpc/rpc/tests/torii.rs +++ b/crates/katana/rpc/rpc/tests/torii.rs @@ -36,7 +36,7 @@ async fn test_get_transactions() { let contract = Arc::new(contract); // Should return successfully when no transactions have been mined. - let cursor = TransactionsPageCursor { block_number: 0, transaction_index: 0 }; + let cursor = TransactionsPageCursor { block_number: 0, transaction_index: 0, chunk_size: 100 }; let response: TransactionsPage = client.get_transactions(cursor).await.unwrap(); @@ -91,7 +91,11 @@ async fn test_get_transactions() { // Should properly increment to new pending block let response: TransactionsPage = client - .get_transactions(TransactionsPageCursor { block_number: 2, transaction_index: 1 }) + .get_transactions(TransactionsPageCursor { + block_number: 2, + transaction_index: 1, + chunk_size: 100, + }) .await .unwrap(); @@ -118,7 +122,7 @@ async fn test_get_transactions() { sleep(Duration::from_millis(5000)).await; let start_cursor = response.cursor; - let response: TransactionsPage = client.get_transactions(start_cursor.clone()).await.unwrap(); + let response: TransactionsPage = client.get_transactions(start_cursor).await.unwrap(); assert!(response.transactions.len() == 100); assert!(response.cursor.block_number == 4); assert!(response.cursor.transaction_index == 100); @@ -132,7 +136,7 @@ async fn test_get_transactions() { // Create block 4. let _: () = client.generate_block().await.unwrap(); - let response: TransactionsPage = client.get_transactions(start_cursor.clone()).await.unwrap(); + let response: TransactionsPage = client.get_transactions(start_cursor).await.unwrap(); assert!(response.transactions.len() == 100); assert!(response.cursor.block_number == 4); assert!(response.cursor.transaction_index == 100); @@ -163,7 +167,7 @@ async fn test_get_transactions_with_instant_mining() { let contract = Arc::new(contract); // Should return successfully when no transactions have been mined. - let cursor = TransactionsPageCursor { block_number: 0, transaction_index: 0 }; + let cursor = TransactionsPageCursor { block_number: 0, transaction_index: 0, chunk_size: 100 }; let declare_res = account.declare(contract.clone(), compiled_class_hash).send().await.unwrap(); @@ -201,7 +205,11 @@ async fn test_get_transactions_with_instant_mining() { // Should properly increment to new pending block let response: TransactionsPage = client - .get_transactions(TransactionsPageCursor { block_number: 2, transaction_index: 1 }) + .get_transactions(TransactionsPageCursor { + block_number: 2, + transaction_index: 1, + chunk_size: 100, + }) .await .unwrap(); diff --git a/crates/katana/storage/db/Cargo.toml b/crates/katana/storage/db/Cargo.toml index 87de9a249d..68c9ac316c 100644 --- a/crates/katana/storage/db/Cargo.toml +++ b/crates/katana/storage/db/Cargo.toml @@ -17,7 +17,6 @@ serde_json.workspace = true tempfile = { version = "3.8.1", optional = true } thiserror.workspace = true -blockifier.workspace = true cairo-vm.workspace = true starknet_api.workspace = true diff --git a/crates/katana/storage/db/benches/codec.rs b/crates/katana/storage/db/benches/codec.rs index fb7f5ab36c..f4e6fbe3b1 100644 --- a/crates/katana/storage/db/benches/codec.rs +++ b/crates/katana/storage/db/benches/codec.rs @@ -1,19 +1,19 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use katana_db::codecs::{Compress, Decompress}; -use katana_db::models::class::StoredContractClass; -use katana_primitives::contract::CompiledContractClass; +use katana_primitives::class::CompiledClass; use katana_primitives::utils::class::parse_compiled_class; -fn compress_contract(contract: CompiledContractClass) -> Vec { - StoredContractClass::from(contract).compress() +fn compress_contract(contract: CompiledClass) -> Vec { + Compress::compress(contract) } -fn decompress_contract(compressed: &[u8]) -> CompiledContractClass { - CompiledContractClass::from(StoredContractClass::decompress(compressed).unwrap()) +fn decompress_contract(compressed: &[u8]) -> CompiledClass { + ::decompress(compressed).unwrap() } fn compress_contract_with_main_codec(c: &mut Criterion) { - let class = parse_compiled_class(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let json = serde_json::from_str(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let class = parse_compiled_class(json).unwrap(); c.bench_function("compress world contract", |b| { b.iter_with_large_drop(|| compress_contract(black_box(class.clone()))) @@ -21,7 +21,8 @@ fn compress_contract_with_main_codec(c: &mut Criterion) { } fn decompress_contract_with_main_codec(c: &mut Criterion) { - let class = parse_compiled_class(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let json = serde_json::from_str(include_str!("./artifacts/dojo_world_240.json")).unwrap(); + let class = parse_compiled_class(json).unwrap(); let compressed = compress_contract(class); c.bench_function("decompress world contract", |b| { diff --git a/crates/katana/storage/db/src/codecs/mod.rs b/crates/katana/storage/db/src/codecs/mod.rs index 622e96921b..c45a2a93f5 100644 --- a/crates/katana/storage/db/src/codecs/mod.rs +++ b/crates/katana/storage/db/src/codecs/mod.rs @@ -2,7 +2,8 @@ pub mod postcard; use katana_primitives::block::FinalityStatus; -use katana_primitives::contract::{ContractAddress, FlattenedSierraClass}; +use katana_primitives::class::FlattenedSierraClass; +use katana_primitives::contract::ContractAddress; use katana_primitives::FieldElement; use crate::error::CodecError; diff --git a/crates/katana/storage/db/src/codecs/postcard.rs b/crates/katana/storage/db/src/codecs/postcard.rs index fa692c5e8d..074bbec480 100644 --- a/crates/katana/storage/db/src/codecs/postcard.rs +++ b/crates/katana/storage/db/src/codecs/postcard.rs @@ -1,13 +1,14 @@ use katana_primitives::block::{BlockNumber, Header}; use katana_primitives::contract::{ContractAddress, GenericContractInfo}; use katana_primitives::receipt::Receipt; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::Tx; use katana_primitives::FieldElement; +use postcard; use super::{Compress, Decompress}; use crate::error::CodecError; use crate::models::block::StoredBlockBodyIndices; -use crate::models::class::StoredContractClass; use crate::models::contract::ContractInfoChangeList; macro_rules! impl_compress_and_decompress_for_table_values { @@ -32,12 +33,12 @@ macro_rules! impl_compress_and_decompress_for_table_values { impl_compress_and_decompress_for_table_values!( u64, Tx, + TxExecInfo, Header, Receipt, FieldElement, ContractAddress, Vec, - StoredContractClass, GenericContractInfo, StoredBlockBodyIndices, ContractInfoChangeList diff --git a/crates/katana/storage/db/src/models/class.rs b/crates/katana/storage/db/src/models/class.rs index 42dd987fc9..3e762f561b 100644 --- a/crates/katana/storage/db/src/models/class.rs +++ b/crates/katana/storage/db/src/models/class.rs @@ -1,519 +1,17 @@ -//! Serializable without using custome functions +use katana_primitives::class::CompiledClass; -use std::collections::HashMap; -use std::num::NonZeroUsize; -use std::sync::Arc; +use crate::codecs::{Compress, Decompress}; +use crate::error::CodecError; -use blockifier::execution::contract_class::{ - ContractClass, ContractClassV0, ContractClassV0Inner, ContractClassV1, ContractClassV1Inner, -}; -use cairo_vm::felt::Felt252; -use cairo_vm::hint_processor::hint_processor_definition::HintReference; -use cairo_vm::serde::deserialize_program::{ - ApTracking, Attribute, BuiltinName, FlowTrackingData, HintParams, Identifier, - InstructionLocation, Member, OffsetValue, -}; -use cairo_vm::types::program::{HintsCollection, Program, SharedProgramData}; -use cairo_vm::types::relocatable::MaybeRelocatable; -use serde::{Deserialize, Serialize}; -use starknet_api::core::EntryPointSelector; -use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}; - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub enum StoredContractClass { - V0(StoredContractClassV0), - V1(StoredContractClassV1), -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct StoredContractClassV0 { - pub program: SerializableProgram, - pub entry_points_by_type: HashMap>, -} - -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] -pub struct StoredContractClassV1 { - pub program: SerializableProgram, - pub hints: HashMap>, - pub entry_points_by_type: HashMap>, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPoint { - pub selector: EntryPointSelector, - pub offset: SerializableEntryPointOffset, -} - -impl From for SerializableEntryPoint { - fn from(value: EntryPoint) -> Self { - Self { selector: value.selector, offset: value.offset.into() } - } -} - -impl From for EntryPoint { - fn from(value: SerializableEntryPoint) -> Self { - Self { selector: value.selector, offset: value.offset.into() } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPointOffset(pub usize); - -impl From for SerializableEntryPointOffset { - fn from(value: EntryPointOffset) -> Self { - Self(value.0) - } -} - -impl From for EntryPointOffset { - fn from(value: SerializableEntryPointOffset) -> Self { - Self(value.0) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableEntryPointV1 { - pub selector: EntryPointSelector, - pub offset: SerializableEntryPointOffset, - pub builtins: Vec, -} - -impl From for blockifier::execution::contract_class::EntryPointV1 { - fn from(value: SerializableEntryPointV1) -> Self { - blockifier::execution::contract_class::EntryPointV1 { - selector: value.selector, - offset: value.offset.into(), - builtins: value.builtins, - } - } -} - -impl From for SerializableEntryPointV1 { - fn from(value: blockifier::execution::contract_class::EntryPointV1) -> Self { - SerializableEntryPointV1 { - selector: value.selector, - offset: value.offset.into(), - builtins: value.builtins, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableProgram { - pub shared_program_data: SerializableSharedProgramData, - pub constants: HashMap, - pub builtins: Vec, -} - -impl From for SerializableProgram { - fn from(value: Program) -> Self { - Self { - shared_program_data: value.shared_program_data.as_ref().clone().into(), - constants: value.constants, - builtins: value.builtins, - } - } -} - -impl From for Program { - fn from(value: SerializableProgram) -> Self { - Self { - shared_program_data: Arc::new(value.shared_program_data.into()), - constants: value.constants, - builtins: value.builtins, - } - } -} - -// Fields of `SerializableProgramData` must not rely on `deserialize_any` -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableSharedProgramData { - pub data: Vec, - pub hints_collection: SerializableHintsCollection, - pub main: Option, - pub start: Option, - pub end: Option, - pub error_message_attributes: Vec, - pub instruction_locations: Option>, - pub identifiers: HashMap, - pub reference_manager: Vec, -} - -impl From for SerializableSharedProgramData { - fn from(value: SharedProgramData) -> Self { - Self { - data: value.data, - hints_collection: value.hints_collection.into(), - main: value.main, - start: value.start, - end: value.end, - error_message_attributes: value - .error_message_attributes - .into_iter() - .map(|a| a.into()) - .collect(), - instruction_locations: value.instruction_locations, - identifiers: value.identifiers.into_iter().map(|(k, v)| (k, v.into())).collect(), - reference_manager: value.reference_manager.into_iter().map(|r| r.into()).collect(), - } - } -} - -impl From for SharedProgramData { - fn from(value: SerializableSharedProgramData) -> Self { - Self { - data: value.data, - hints_collection: value.hints_collection.into(), - main: value.main, - start: value.start, - end: value.end, - error_message_attributes: value - .error_message_attributes - .into_iter() - .map(|a| a.into()) - .collect(), - instruction_locations: value.instruction_locations, - identifiers: value.identifiers.into_iter().map(|(k, v)| (k, v.into())).collect(), - reference_manager: value.reference_manager.into_iter().map(|r| r.into()).collect(), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintParams { - pub code: String, - pub accessible_scopes: Vec, - pub flow_tracking_data: SerializableFlowTrackingData, -} - -impl From for SerializableHintParams { - fn from(value: HintParams) -> Self { - Self { - code: value.code, - accessible_scopes: value.accessible_scopes, - flow_tracking_data: value.flow_tracking_data.into(), - } - } -} - -impl From for HintParams { - fn from(value: SerializableHintParams) -> Self { - Self { - code: value.code, - accessible_scopes: value.accessible_scopes, - flow_tracking_data: value.flow_tracking_data.into(), - } - } -} - -type HintRange = Option<(usize, NonZeroUsize)>; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintsCollection { - pub hints: Vec, - pub hints_ranges: Vec, -} - -impl From for SerializableHintsCollection { - fn from(value: HintsCollection) -> Self { - Self { - hints_ranges: value.hints_ranges, - hints: value.hints.into_iter().map(|h| h.into()).collect(), - } - } -} - -impl From for HintsCollection { - fn from(value: SerializableHintsCollection) -> Self { - Self { - hints_ranges: value.hints_ranges, - hints: value.hints.into_iter().map(|h| h.into()).collect(), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableIdentifier { - pub pc: Option, - pub type_: Option, - pub value: Option, - pub full_name: Option, - pub members: Option>, - pub cairo_type: Option, -} - -impl From for SerializableIdentifier { - fn from(value: Identifier) -> Self { - Self { - pc: value.pc, - type_: value.type_, - value: value.value, - full_name: value.full_name, - members: value.members, - cairo_type: value.cairo_type, - } - } -} - -impl From for Identifier { - fn from(value: SerializableIdentifier) -> Self { - Self { - pc: value.pc, - type_: value.type_, - value: value.value, - full_name: value.full_name, - members: value.members, - cairo_type: value.cairo_type, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableHintReference { - pub offset1: OffsetValue, - pub offset2: OffsetValue, - pub dereference: bool, - pub ap_tracking_data: Option, - pub cairo_type: Option, -} - -impl From for SerializableHintReference { - fn from(value: HintReference) -> Self { - Self { - offset1: value.offset1, - offset2: value.offset2, - dereference: value.dereference, - ap_tracking_data: value.ap_tracking_data, - cairo_type: value.cairo_type, - } - } -} - -impl From for HintReference { - fn from(value: SerializableHintReference) -> Self { - Self { - offset1: value.offset1, - offset2: value.offset2, - dereference: value.dereference, - ap_tracking_data: value.ap_tracking_data, - cairo_type: value.cairo_type, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableAttribute { - pub name: String, - pub start_pc: usize, - pub end_pc: usize, - pub value: String, - pub flow_tracking_data: Option, -} - -impl From for SerializableAttribute { - fn from(value: Attribute) -> Self { - Self { - name: value.name, - start_pc: value.start_pc, - end_pc: value.end_pc, - value: value.value, - flow_tracking_data: value.flow_tracking_data.map(|d| d.into()), - } - } -} - -impl From for Attribute { - fn from(value: SerializableAttribute) -> Self { - Self { - name: value.name, - start_pc: value.start_pc, - end_pc: value.end_pc, - value: value.value, - flow_tracking_data: value.flow_tracking_data.map(|d| d.into()), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct SerializableFlowTrackingData { - pub ap_tracking: ApTracking, - pub reference_ids: HashMap, -} - -impl From for SerializableFlowTrackingData { - fn from(value: FlowTrackingData) -> Self { - Self { ap_tracking: value.ap_tracking, reference_ids: value.reference_ids } +impl Compress for CompiledClass { + type Compressed = Vec; + fn compress(self) -> Self::Compressed { + serde_json::to_vec(&self).unwrap() } } -impl From for FlowTrackingData { - fn from(value: SerializableFlowTrackingData) -> Self { - Self { ap_tracking: value.ap_tracking, reference_ids: value.reference_ids } - } -} - -impl From for ContractClass { - fn from(value: StoredContractClass) -> Self { - match value { - StoredContractClass::V0(v0) => { - ContractClass::V0(ContractClassV0(Arc::new(ContractClassV0Inner { - program: v0.program.into(), - entry_points_by_type: v0 - .entry_points_by_type - .into_iter() - .map(|(k, v)| (k, v.into_iter().map(|h| h.into()).collect())) - .collect(), - }))) - } - StoredContractClass::V1(v1) => { - ContractClass::V1(ContractClassV1(Arc::new(ContractClassV1Inner { - hints: v1 - .hints - .clone() - .into_iter() - .map(|(k, v)| (k, serde_json::from_slice(&v).expect("valid hint"))) - .collect(), - program: v1.program.into(), - entry_points_by_type: v1 - .entry_points_by_type - .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .map(Into::into) - .collect::>(), - ) - }) - .collect::>(), - }))) - } - } - } -} - -impl From for StoredContractClass { - fn from(value: ContractClass) -> Self { - match value { - ContractClass::V0(v0) => { - let entry_points_by_type = v0 - .entry_points_by_type - .clone() - .into_iter() - .map(|(k, v)| (k, v.into_iter().map(SerializableEntryPoint::from).collect())) - .collect(); - - StoredContractClass::V0(StoredContractClassV0 { - program: v0.program.clone().into(), - entry_points_by_type, - }) - } - - ContractClass::V1(v1) => StoredContractClass::V1(StoredContractClassV1 { - program: v1.program.clone().into(), - entry_points_by_type: v1 - .entry_points_by_type - .clone() - .into_iter() - .map(|(k, v)| { - ( - k, - v.into_iter() - .map(Into::into) - .collect::>(), - ) - }) - .collect::>(), - hints: v1 - .hints - .clone() - .into_iter() - .map(|(k, v)| (k, serde_json::to_vec(&v).expect("valid hint"))) - .collect(), - }), - } - } -} - -#[cfg(test)] -mod tests { - use cairo_lang_starknet::casm_contract_class::CasmContractClass; - use katana_primitives::contract::CompiledContractClass; - use starknet_api::hash::StarkFelt; - use starknet_api::stark_felt; - - use super::*; - use crate::codecs::{Compress, Decompress}; - - #[test] - fn serialize_deserialize_legacy_entry_points() { - let non_serde = vec![ - EntryPoint { - offset: EntryPointOffset(0x25f), - selector: EntryPointSelector(stark_felt!( - "0x289da278a8dc833409cabfdad1581e8e7d40e42dcaed693fa4008dcdb4963b3" - )), - }, - EntryPoint { - offset: EntryPointOffset(0x1b2), - selector: EntryPointSelector(stark_felt!( - "0x29e211664c0b63c79638fbea474206ca74016b3e9a3dc4f9ac300ffd8bdf2cd" - )), - }, - EntryPoint { - offset: EntryPointOffset(0x285), - selector: EntryPointSelector(stark_felt!( - "0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895" - )), - }, - ]; - - // convert to serde and back - let serde: Vec = - non_serde.iter().map(|e| e.clone().into()).collect(); - - // convert to json - let json = serde_json::to_vec(&serde).unwrap(); - let serde: Vec = serde_json::from_slice(&json).unwrap(); - - let same_non_serde: Vec = serde.iter().map(|e| e.clone().into()).collect(); - - assert_eq!(non_serde, same_non_serde); - } - - #[test] - fn compress_and_decompress_contract_class() { - let class = - serde_json::from_slice(include_bytes!("../../benches/artifacts/dojo_world_240.json")) - .unwrap(); - - let class = CasmContractClass::from_contract_class(class, true).unwrap(); - let class = CompiledContractClass::V1(ContractClassV1::try_from(class).unwrap()); - - let compressed = StoredContractClass::from(class.clone()).compress(); - let decompressed = ::decompress(compressed).unwrap(); - - let actual_class = CompiledContractClass::from(decompressed); - - assert_eq!(class, actual_class); - } - - #[test] - fn compress_and_decompress_legacy_contract_class() { - let class: ContractClassV0 = serde_json::from_slice(include_bytes!( - "../../../../primitives/contracts/compiled/account.json" - )) - .unwrap(); - - let class = CompiledContractClass::V0(class); - - let compressed = StoredContractClass::from(class.clone()).compress(); - let decompressed = ::decompress(compressed).unwrap(); - - let actual_class = CompiledContractClass::from(decompressed); - - assert_eq!(class, actual_class); +impl Decompress for CompiledClass { + fn decompress>(bytes: B) -> Result { + serde_json::from_slice(bytes.as_ref()).map_err(|e| CodecError::Decode(e.to_string())) } } diff --git a/crates/katana/storage/db/src/models/contract.rs b/crates/katana/storage/db/src/models/contract.rs index 25c9818671..73f5025d0c 100644 --- a/crates/katana/storage/db/src/models/contract.rs +++ b/crates/katana/storage/db/src/models/contract.rs @@ -1,5 +1,6 @@ use katana_primitives::block::BlockNumber; -use katana_primitives::contract::{ClassHash, ContractAddress, Nonce}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::{ContractAddress, Nonce}; use serde::{Deserialize, Serialize}; use crate::codecs::{Compress, Decode, Decompress, Encode}; diff --git a/crates/katana/storage/db/src/tables.rs b/crates/katana/storage/db/src/tables.rs index 4af836df20..b42f431e8e 100644 --- a/crates/katana/storage/db/src/tables.rs +++ b/crates/katana/storage/db/src/tables.rs @@ -1,14 +1,12 @@ use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, ContractAddress, FlattenedSierraClass, GenericContractInfo, - StorageKey, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, GenericContractInfo, StorageKey}; use katana_primitives::receipt::Receipt; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{Tx, TxHash, TxNumber}; use crate::codecs::{Compress, Decode, Decompress, Encode}; use crate::models::block::StoredBlockBodyIndices; -use crate::models::class::StoredContractClass; use crate::models::contract::{ContractClassChange, ContractInfoChangeList, ContractNonceChange}; use crate::models::storage::{ ContractStorageEntry, ContractStorageKey, StorageEntry, StorageEntryChangeList, @@ -159,7 +157,7 @@ define_tables_enum! {[ (Transactions, TableType::Table), (Receipts, TableType::Table), (CompiledClassHashes, TableType::Table), - (CompiledContractClasses, TableType::Table), + (CompiledClasses, TableType::Table), (SierraClasses, TableType::Table), (ContractInfo, TableType::Table), (ContractStorage, TableType::DupSort), @@ -192,12 +190,14 @@ tables! { Transactions: (TxNumber) => Tx, /// Stores the block number of a transaction. TxBlocks: (TxNumber) => BlockNumber, + /// Stores the transaction's execution info. + TxExecutions: (TxNumber) => TxExecInfo, /// Store transaction receipts Receipts: (TxNumber) => Receipt, /// Store compiled classes CompiledClassHashes: (ClassHash) => CompiledClassHash, /// Store compiled contract classes according to its compiled class hash - CompiledContractClasses: (ClassHash) => StoredContractClass, + CompiledClasses: (ClassHash) => CompiledClass, /// Store Sierra classes according to its class hash SierraClasses: (ClassHash) => FlattenedSierraClass, /// Store contract information according to its contract address @@ -246,7 +246,7 @@ mod tests { assert_eq!(Tables::ALL[8].name(), Transactions::NAME); assert_eq!(Tables::ALL[9].name(), Receipts::NAME); assert_eq!(Tables::ALL[10].name(), CompiledClassHashes::NAME); - assert_eq!(Tables::ALL[11].name(), CompiledContractClasses::NAME); + assert_eq!(Tables::ALL[11].name(), CompiledClasses::NAME); assert_eq!(Tables::ALL[12].name(), SierraClasses::NAME); assert_eq!(Tables::ALL[13].name(), ContractInfo::NAME); assert_eq!(Tables::ALL[14].name(), ContractStorage::NAME); diff --git a/crates/katana/storage/provider/Cargo.toml b/crates/katana/storage/provider/Cargo.toml index befc4db468..39b0345385 100644 --- a/crates/katana/storage/provider/Cargo.toml +++ b/crates/katana/storage/provider/Cargo.toml @@ -31,8 +31,8 @@ katana-core = { path = "../../core" } katana-runner.workspace = true lazy_static.workspace = true rand = "0.8.5" -rstest = "0.18.2" -rstest_reuse = "0.6.0" +rstest.workspace = true +rstest_reuse.workspace = true serde_json.workspace = true starknet.workspace = true tempfile = "3.8.1" diff --git a/crates/katana/storage/provider/src/error.rs b/crates/katana/storage/provider/src/error.rs index 97cf5515a9..6fe75d4c6d 100644 --- a/crates/katana/storage/provider/src/error.rs +++ b/crates/katana/storage/provider/src/error.rs @@ -1,6 +1,7 @@ use katana_db::error::DatabaseError; use katana_primitives::block::BlockNumber; -use katana_primitives::contract::{ClassHash, ContractAddress, StorageKey}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::{ContractAddress, StorageKey}; use katana_primitives::transaction::TxNumber; use crate::providers::fork::backend::ForkedBackendError; @@ -104,4 +105,8 @@ pub enum ProviderError { #[cfg(feature = "fork")] #[error(transparent)] ForkedBackend(#[from] ForkedBackendError), + + /// Any error that is not covered by the other variants. + #[error("soemthing went wrong: {0}")] + Other(String), } diff --git a/crates/katana/storage/provider/src/lib.rs b/crates/katana/storage/provider/src/lib.rs index baf44e836f..c14e408af3 100644 --- a/crates/katana/storage/provider/src/lib.rs +++ b/crates/katana/storage/provider/src/lib.rs @@ -5,20 +5,19 @@ use katana_primitives::block::{ Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithTxHashes, FinalityStatus, Header, SealedBlockWithStatus, }; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, StorageKey, StorageValue, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, GenericContractInfo, StorageKey, StorageValue}; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{TxHash, TxNumber, TxWithHash}; use katana_primitives::FieldElement; use traits::block::{BlockIdReader, BlockStatusProvider, BlockWriter}; use traits::contract::{ContractClassProvider, ContractClassWriter}; use traits::env::BlockEnvProvider; use traits::state::{StateRootProvider, StateWriter}; -use traits::transaction::TransactionStatusProvider; +use traits::transaction::{TransactionStatusProvider, TransactionTraceProvider}; pub mod error; pub mod providers; @@ -129,8 +128,9 @@ where block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, receipts: Vec, + executions: Vec, ) -> ProviderResult<()> { - self.provider.insert_block_with_states_and_receipts(block, states, receipts) + self.provider.insert_block_with_states_and_receipts(block, states, receipts, executions) } } @@ -185,6 +185,22 @@ where } } +impl TransactionTraceProvider for BlockchainProvider +where + Db: TransactionTraceProvider, +{ + fn transaction_execution(&self, hash: TxHash) -> ProviderResult> { + TransactionTraceProvider::transaction_execution(&self.provider, hash) + } + + fn transactions_executions_by_block( + &self, + block_id: BlockHashOrNumber, + ) -> ProviderResult>> { + TransactionTraceProvider::transactions_executions_by_block(&self.provider, block_id) + } +} + impl TransactionsProviderExt for BlockchainProvider where Db: TransactionsProviderExt, @@ -248,7 +264,7 @@ where self.provider.compiled_class_hash_of_class_hash(hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { self.provider.class(hash) } @@ -304,7 +320,7 @@ impl ContractClassWriter for BlockchainProvider where Db: ContractClassWriter, { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.provider.set_class(hash, class) } diff --git a/crates/katana/storage/provider/src/providers/db/mod.rs b/crates/katana/storage/provider/src/providers/db/mod.rs index bf5ad85ca7..d59aa8b684 100644 --- a/crates/katana/storage/provider/src/providers/db/mod.rs +++ b/crates/katana/storage/provider/src/providers/db/mod.rs @@ -19,13 +19,14 @@ use katana_primitives::block::{ Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithTxHashes, FinalityStatus, Header, SealedBlockWithStatus, }; +use katana_primitives::class::{ClassHash, CompiledClassHash}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, ContractAddress, GenericContractInfo, Nonce, StorageKey, - StorageValue, + ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{TxHash, TxNumber, TxWithHash}; use katana_primitives::FieldElement; @@ -38,7 +39,8 @@ use crate::traits::env::BlockEnvProvider; use crate::traits::state::{StateFactoryProvider, StateProvider, StateRootProvider}; use crate::traits::state_update::StateUpdateProvider; use crate::traits::transaction::{ - ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionsProviderExt, + ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionTraceProvider, + TransactionsProviderExt, }; use crate::ProviderResult; @@ -490,6 +492,19 @@ impl TransactionStatusProvider for DbProvider { } } +impl TransactionTraceProvider for DbProvider { + fn transaction_execution(&self, _hash: TxHash) -> ProviderResult> { + todo!() + } + + fn transactions_executions_by_block( + &self, + _block_id: BlockHashOrNumber, + ) -> ProviderResult>> { + todo!() + } +} + impl ReceiptProvider for DbProvider { fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult> { let db_tx = self.0.tx()?; @@ -547,6 +562,7 @@ impl BlockWriter for DbProvider { block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, receipts: Vec, + _executions: Vec, ) -> ProviderResult<()> { self.0.update(move |db_tx| -> ProviderResult<()> { let block_hash = block.block.header.hash; @@ -587,7 +603,7 @@ impl BlockWriter for DbProvider { } for (hash, compiled_class) in states.declared_compiled_classes { - db_tx.put::(hash, compiled_class.into())?; + db_tx.put::(hash, compiled_class)?; } for (class_hash, sierra_class) in states.declared_sierra_classes { @@ -805,6 +821,7 @@ mod tests { block.clone(), state_updates, vec![Receipt::Invoke(Default::default())], + vec![], ) .expect("failed to insert block"); @@ -882,6 +899,7 @@ mod tests { block.clone(), state_updates1, vec![Receipt::Invoke(Default::default())], + vec![], ) .expect("failed to insert block"); @@ -891,6 +909,7 @@ mod tests { block, state_updates2, vec![Receipt::Invoke(Default::default())], + vec![], ) .expect("failed to insert block"); diff --git a/crates/katana/storage/provider/src/providers/db/state.rs b/crates/katana/storage/provider/src/providers/db/state.rs index e72b5cfbd1..381e60063c 100644 --- a/crates/katana/storage/provider/src/providers/db/state.rs +++ b/crates/katana/storage/provider/src/providers/db/state.rs @@ -5,9 +5,9 @@ use katana_db::models::contract::ContractInfoChangeList; use katana_db::models::storage::{ContractStorageKey, StorageEntry}; use katana_db::tables; use katana_primitives::block::BlockNumber; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, Nonce, StorageKey, StorageValue, + ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use super::DbProvider; @@ -69,9 +69,9 @@ impl StateWriter for DbProvider { } impl ContractClassWriter for DbProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.0.update(move |db_tx| -> ProviderResult<()> { - db_tx.put::(hash, class.into())?; + db_tx.put::(hash, class)?; Ok(()) })? } @@ -109,9 +109,9 @@ impl LatestStateProvider { } impl ContractClassProvider for LatestStateProvider { - fn class(&self, hash: ClassHash) -> ProviderResult> { - let class = self.0.get::(hash)?; - Ok(class.map(CompiledContractClass::from)) + fn class(&self, hash: ClassHash) -> ProviderResult> { + let class = self.0.get::(hash)?; + Ok(class) } fn compiled_class_hash_of_class_hash( @@ -137,7 +137,7 @@ impl StateProvider for LatestStateProvider { fn class_hash_of_contract( &self, address: ContractAddress, - ) -> ProviderResult> { + ) -> ProviderResult> { let info = self.0.get::(address)?; Ok(info.map(|info| info.class_hash)) } @@ -222,10 +222,10 @@ impl ContractClassProvider for HistoricalStateProvider { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.compiled_class_hash_of_class_hash(hash)?.is_some() { - let contract = self.tx.get::(hash)?; - Ok(contract.map(CompiledContractClass::from)) + let contract = self.tx.get::(hash)?; + Ok(contract) } else { Ok(None) } diff --git a/crates/katana/storage/provider/src/providers/fork/backend.rs b/crates/katana/storage/provider/src/providers/fork/backend.rs index 41f92f63f2..45052b8eef 100644 --- a/crates/katana/storage/provider/src/providers/fork/backend.rs +++ b/crates/katana/storage/provider/src/providers/fork/backend.rs @@ -10,13 +10,13 @@ use futures::future::BoxFuture; use futures::stream::Stream; use futures::{Future, FutureExt}; use katana_primitives::block::BlockHashOrNumber; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, Nonce, StorageKey, StorageValue, + ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use katana_primitives::conversion::rpc::{ compiled_class_hash_from_flattened_sierra_class, flattened_sierra_to_compiled_class, - legacy_rpc_to_inner_compiled_class, + legacy_rpc_to_compiled_class, }; use katana_primitives::FieldElement; use parking_lot::Mutex; @@ -449,7 +449,7 @@ impl ContractClassProvider for SharedStateProvider { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if let Some(class) = self.0.shared_contract_classes.compiled_classes.read().get(&hash) { return Ok(Some(class.clone())); } @@ -465,7 +465,7 @@ impl ContractClassProvider for SharedStateProvider { let (class_hash, compiled_class_hash, casm, sierra) = match class { ContractClass::Legacy(class) => { - let (_, compiled_class) = legacy_rpc_to_inner_compiled_class(&class).map_err(|e| { + let (_, compiled_class) = legacy_rpc_to_compiled_class(&class).map_err(|e| { error!(target: "forked_backend", "error while parsing legacy class {hash:#x}: {e}"); ProviderError::ParsingError(e.to_string()) })?; diff --git a/crates/katana/storage/provider/src/providers/fork/mod.rs b/crates/katana/storage/provider/src/providers/fork/mod.rs index 0f1f6558f5..98a2bd991e 100644 --- a/crates/katana/storage/provider/src/providers/fork/mod.rs +++ b/crates/katana/storage/provider/src/providers/fork/mod.rs @@ -9,12 +9,12 @@ use katana_primitives::block::{ Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithTxHashes, FinalityStatus, Header, SealedBlockWithStatus, }; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::ContractAddress; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{Tx, TxHash, TxNumber, TxWithHash}; use parking_lot::RwLock; use starknet::providers::jsonrpc::HttpTransport; @@ -33,7 +33,8 @@ use crate::traits::env::BlockEnvProvider; use crate::traits::state::{StateFactoryProvider, StateProvider, StateRootProvider, StateWriter}; use crate::traits::state_update::StateUpdateProvider; use crate::traits::transaction::{ - ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionsProviderExt, + ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionTraceProvider, + TransactionsProviderExt, }; use crate::ProviderResult; @@ -322,6 +323,47 @@ impl TransactionStatusProvider for ForkedProvider { } } +impl TransactionTraceProvider for ForkedProvider { + fn transaction_execution(&self, hash: TxHash) -> ProviderResult> { + let exec = self.storage.read().transaction_numbers.get(&hash).and_then(|num| { + self.storage.read().transactions_executions.get(*num as usize).cloned() + }); + + Ok(exec) + } + + fn transactions_executions_by_block( + &self, + block_id: BlockHashOrNumber, + ) -> ProviderResult>> { + let block_num = match block_id { + BlockHashOrNumber::Num(num) => Some(num), + BlockHashOrNumber::Hash(hash) => self.storage.read().block_numbers.get(&hash).cloned(), + }; + + let Some(StoredBlockBodyIndices { tx_offset, tx_count }) = + block_num.and_then(|num| self.storage.read().block_body_indices.get(&num).cloned()) + else { + return Ok(None); + }; + + let offset = tx_offset as usize; + let count = tx_count as usize; + + let execs = self + .storage + .read() + .transactions_executions + .iter() + .skip(offset) + .take(count) + .cloned() + .collect(); + + Ok(Some(execs)) + } +} + impl ReceiptProvider for ForkedProvider { fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult> { let receipt = self @@ -414,6 +456,7 @@ impl BlockWriter for ForkedProvider { block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, receipts: Vec, + _executions: Vec, ) -> ProviderResult<()> { let mut storage = self.storage.write(); @@ -464,7 +507,7 @@ impl BlockWriter for ForkedProvider { } impl ContractClassWriter for ForkedProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.state.shared_contract_classes.compiled_classes.write().insert(hash, class); Ok(()) } diff --git a/crates/katana/storage/provider/src/providers/fork/state.rs b/crates/katana/storage/provider/src/providers/fork/state.rs index a607f27f6d..ba35a010d5 100644 --- a/crates/katana/storage/provider/src/providers/fork/state.rs +++ b/crates/katana/storage/provider/src/providers/fork/state.rs @@ -1,8 +1,8 @@ use std::sync::Arc; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, Nonce, StorageKey, StorageValue, + ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use super::backend::SharedStateProvider; @@ -83,7 +83,7 @@ impl ContractClassProvider for CacheStateDb { ContractClassProvider::compiled_class_hash_of_class_hash(&self.db, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if let class @ Some(_) = self.shared_contract_classes.compiled_classes.read().get(&hash) { return Ok(class.cloned()); } @@ -125,7 +125,7 @@ impl ContractClassProvider for LatestStateProvider { ContractClassProvider::sierra_class(&self.0, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { ContractClassProvider::class(&self.0, hash) } @@ -199,7 +199,7 @@ impl ContractClassProvider for ForkedSnapshot { ContractClassProvider::compiled_class_hash_of_class_hash(&self.inner.db, hash) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.inner.compiled_class_hashes.get(&hash).is_some() { Ok(self.classes.compiled_classes.read().get(&hash).cloned()) } else { diff --git a/crates/katana/storage/provider/src/providers/in_memory/cache.rs b/crates/katana/storage/provider/src/providers/in_memory/cache.rs index 43ad2a33e8..6bd193b08c 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/cache.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/cache.rs @@ -3,12 +3,11 @@ use std::sync::Arc; use katana_db::models::block::StoredBlockBodyIndices; use katana_primitives::block::{BlockHash, BlockNumber, FinalityStatus, Header}; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, StorageKey, StorageValue, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, GenericContractInfo, StorageKey, StorageValue}; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{Tx, TxHash, TxNumber}; use parking_lot::RwLock; @@ -16,7 +15,7 @@ type ContractStorageMap = HashMap; type SierraClassesMap = HashMap; -type CompiledClassesMap = HashMap; +type CompiledClassesMap = HashMap; type CompiledClassHashesMap = HashMap; #[derive(Default)] @@ -82,6 +81,7 @@ pub struct CacheDb { pub(crate) state_update: HashMap, pub(crate) receipts: Vec, pub(crate) transactions: Vec, + pub(crate) transactions_executions: Vec, pub(crate) transaction_hashes: HashMap, pub(crate) transaction_numbers: HashMap, pub(crate) transaction_block: HashMap, @@ -114,6 +114,7 @@ impl CacheDb { transaction_hashes: HashMap::new(), block_body_indices: HashMap::new(), transaction_numbers: HashMap::new(), + transactions_executions: Vec::new(), latest_block_hash: Default::default(), latest_block_number: Default::default(), } diff --git a/crates/katana/storage/provider/src/providers/in_memory/mod.rs b/crates/katana/storage/provider/src/providers/in_memory/mod.rs index daaef199dd..82b704cb29 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/mod.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/mod.rs @@ -9,12 +9,12 @@ use katana_primitives::block::{ Block, BlockHash, BlockHashOrNumber, BlockNumber, BlockWithTxHashes, FinalityStatus, Header, SealedBlockWithStatus, }; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::ContractAddress; use katana_primitives::env::BlockEnv; use katana_primitives::receipt::Receipt; use katana_primitives::state::{StateUpdates, StateUpdatesWithDeclaredClasses}; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{Tx, TxHash, TxNumber, TxWithHash}; use parking_lot::RwLock; @@ -29,7 +29,8 @@ use crate::traits::env::BlockEnvProvider; use crate::traits::state::{StateFactoryProvider, StateProvider, StateRootProvider, StateWriter}; use crate::traits::state_update::StateUpdateProvider; use crate::traits::transaction::{ - ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionsProviderExt, + ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionTraceProvider, + TransactionsProviderExt, }; use crate::ProviderResult; @@ -316,6 +317,47 @@ impl TransactionStatusProvider for InMemoryProvider { } } +impl TransactionTraceProvider for InMemoryProvider { + fn transaction_execution(&self, hash: TxHash) -> ProviderResult> { + let exec = self.storage.read().transaction_numbers.get(&hash).and_then(|num| { + self.storage.read().transactions_executions.get(*num as usize).cloned() + }); + + Ok(exec) + } + + fn transactions_executions_by_block( + &self, + block_id: BlockHashOrNumber, + ) -> ProviderResult>> { + let block_num = match block_id { + BlockHashOrNumber::Num(num) => Some(num), + BlockHashOrNumber::Hash(hash) => self.storage.read().block_numbers.get(&hash).cloned(), + }; + + let Some(StoredBlockBodyIndices { tx_offset, tx_count }) = + block_num.and_then(|num| self.storage.read().block_body_indices.get(&num).cloned()) + else { + return Ok(None); + }; + + let offset = tx_offset as usize; + let count = tx_count as usize; + + let execs = self + .storage + .read() + .transactions_executions + .iter() + .skip(offset) + .take(count) + .cloned() + .collect(); + + Ok(Some(execs)) + } +} + impl ReceiptProvider for InMemoryProvider { fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult> { let receipt = self @@ -408,6 +450,7 @@ impl BlockWriter for InMemoryProvider { block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, receipts: Vec, + executions: Vec, ) -> ProviderResult<()> { let mut storage = self.storage.write(); @@ -441,6 +484,7 @@ impl BlockWriter for InMemoryProvider { storage.block_body_indices.insert(block_number, block_body_indices); storage.transactions.extend(txs); + storage.transactions_executions.extend(executions); storage.transaction_hashes.extend(txs_id); storage.transaction_numbers.extend(txs_num); storage.transaction_block.extend(txs_block); @@ -458,7 +502,7 @@ impl BlockWriter for InMemoryProvider { } impl ContractClassWriter for InMemoryProvider { - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()> { + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()> { self.state.shared_contract_classes.compiled_classes.write().insert(hash, class); Ok(()) } diff --git a/crates/katana/storage/provider/src/providers/in_memory/state.rs b/crates/katana/storage/provider/src/providers/in_memory/state.rs index aba2343a74..a481d7c21f 100644 --- a/crates/katana/storage/provider/src/providers/in_memory/state.rs +++ b/crates/katana/storage/provider/src/providers/in_memory/state.rs @@ -2,9 +2,9 @@ use std::collections::{HashMap, VecDeque}; use std::sync::Arc; use katana_primitives::block::BlockNumber; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, Nonce, StorageKey, StorageValue, + ContractAddress, GenericContractInfo, Nonce, StorageKey, StorageValue, }; use super::cache::{CacheSnapshotWithoutClasses, CacheStateDb, SharedContractClasses}; @@ -157,7 +157,7 @@ impl ContractClassProvider for InMemorySnapshot { } } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { if self.compiled_class_hash_of_class_hash(hash)?.is_some() { Ok(self.classes.compiled_classes.read().get(&hash).cloned()) } else { @@ -213,7 +213,7 @@ impl ContractClassProvider for LatestStateProvider { Ok(class) } - fn class(&self, hash: ClassHash) -> ProviderResult> { + fn class(&self, hash: ClassHash) -> ProviderResult> { let class = self.0.shared_contract_classes.compiled_classes.read().get(&hash).cloned(); Ok(class) } diff --git a/crates/katana/storage/provider/src/traits/block.rs b/crates/katana/storage/provider/src/traits/block.rs index ea8085564e..070d016210 100644 --- a/crates/katana/storage/provider/src/traits/block.rs +++ b/crates/katana/storage/provider/src/traits/block.rs @@ -7,6 +7,7 @@ use katana_primitives::block::{ }; use katana_primitives::receipt::Receipt; use katana_primitives::state::StateUpdatesWithDeclaredClasses; +use katana_primitives::trace::TxExecInfo; use super::transaction::{TransactionProvider, TransactionsProviderExt}; use crate::ProviderResult; @@ -147,5 +148,6 @@ pub trait BlockWriter: Send + Sync { block: SealedBlockWithStatus, states: StateUpdatesWithDeclaredClasses, receipts: Vec, + executions: Vec, ) -> ProviderResult<()>; } diff --git a/crates/katana/storage/provider/src/traits/contract.rs b/crates/katana/storage/provider/src/traits/contract.rs index d8ea80ccb5..7ff77f1999 100644 --- a/crates/katana/storage/provider/src/traits/contract.rs +++ b/crates/katana/storage/provider/src/traits/contract.rs @@ -1,7 +1,5 @@ -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, ContractAddress, FlattenedSierraClass, - GenericContractInfo, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; +use katana_primitives::contract::{ContractAddress, GenericContractInfo}; use crate::ProviderResult; @@ -21,7 +19,7 @@ pub trait ContractClassProvider: Send + Sync { ) -> ProviderResult>; /// Returns the compiled class definition of a contract class given its class hash. - fn class(&self, hash: ClassHash) -> ProviderResult>; + fn class(&self, hash: ClassHash) -> ProviderResult>; /// Retrieves the Sierra class definition of a contract class given its class hash. fn sierra_class(&self, hash: ClassHash) -> ProviderResult>; @@ -38,7 +36,7 @@ pub trait ContractClassWriter: Send + Sync { ) -> ProviderResult<()>; /// Returns the compiled class definition of a contract class given its class hash. - fn set_class(&self, hash: ClassHash, class: CompiledContractClass) -> ProviderResult<()>; + fn set_class(&self, hash: ClassHash, class: CompiledClass) -> ProviderResult<()>; /// Retrieves the Sierra class definition of a contract class given its class hash. fn set_sierra_class(&self, hash: ClassHash, sierra: FlattenedSierraClass) diff --git a/crates/katana/storage/provider/src/traits/state.rs b/crates/katana/storage/provider/src/traits/state.rs index 279769d71b..3ec9aade09 100644 --- a/crates/katana/storage/provider/src/traits/state.rs +++ b/crates/katana/storage/provider/src/traits/state.rs @@ -1,5 +1,6 @@ use katana_primitives::block::BlockHashOrNumber; -use katana_primitives::contract::{ClassHash, ContractAddress, Nonce, StorageKey, StorageValue}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::{ContractAddress, Nonce, StorageKey, StorageValue}; use katana_primitives::FieldElement; use super::contract::ContractClassProvider; diff --git a/crates/katana/storage/provider/src/traits/transaction.rs b/crates/katana/storage/provider/src/traits/transaction.rs index 6237eaf69d..6054f0c3c0 100644 --- a/crates/katana/storage/provider/src/traits/transaction.rs +++ b/crates/katana/storage/provider/src/traits/transaction.rs @@ -2,6 +2,7 @@ use std::ops::Range; use katana_primitives::block::{BlockHash, BlockHashOrNumber, BlockNumber, FinalityStatus}; use katana_primitives::receipt::Receipt; +use katana_primitives::trace::TxExecInfo; use katana_primitives::transaction::{TxHash, TxNumber, TxWithHash}; use crate::ProviderResult; @@ -52,6 +53,18 @@ pub trait TransactionStatusProvider: Send + Sync { fn transaction_status(&self, hash: TxHash) -> ProviderResult>; } +#[auto_impl::auto_impl(&, Box, Arc)] +pub trait TransactionTraceProvider: Send + Sync { + /// Returns a transaction execution given its hash. + fn transaction_execution(&self, hash: TxHash) -> ProviderResult>; + + /// Returns all the transactions executions for a given block. + fn transactions_executions_by_block( + &self, + block_id: BlockHashOrNumber, + ) -> ProviderResult>>; +} + #[auto_impl::auto_impl(&, Box, Arc)] pub trait ReceiptProvider: Send + Sync { /// Returns the transaction receipt given a transaction hash. diff --git a/crates/katana/storage/provider/tests/block.rs b/crates/katana/storage/provider/tests/block.rs index 2146eeef8f..83861e52a4 100644 --- a/crates/katana/storage/provider/tests/block.rs +++ b/crates/katana/storage/provider/tests/block.rs @@ -72,6 +72,7 @@ where block.clone(), Default::default(), receipts.clone(), + Default::default(), )?; assert_eq!(provider.latest_number().unwrap(), block.block.header.header.number); diff --git a/crates/katana/storage/provider/tests/class.rs b/crates/katana/storage/provider/tests/class.rs index b0c9cf9d65..3e850b83c8 100644 --- a/crates/katana/storage/provider/tests/class.rs +++ b/crates/katana/storage/provider/tests/class.rs @@ -6,9 +6,7 @@ use fixtures::{ DOJO_WORLD_COMPILED_CLASS, DOJO_WORLD_SIERRA_CLASS, }; use katana_primitives::block::{BlockHashOrNumber, BlockNumber}; -use katana_primitives::contract::{ - ClassHash, CompiledClassHash, CompiledContractClass, FlattenedSierraClass, -}; +use katana_primitives::class::{ClassHash, CompiledClass, CompiledClassHash, FlattenedSierraClass}; use katana_primitives::genesis::constant::{ DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, }; @@ -19,12 +17,8 @@ use katana_provider::BlockchainProvider; use rstest_reuse::{self, *}; use starknet::macros::felt; -type ClassHashAndClasses = ( - ClassHash, - Option, - Option, - Option, -); +type ClassHashAndClasses = + (ClassHash, Option, Option, Option); fn assert_state_provider_class( state_provider: Box, @@ -38,7 +32,7 @@ fn assert_state_provider_class( let actual_sierra_class = state_provider.sierra_class(class_hash)?; assert!( - if let Some(CompiledContractClass::V1(_)) = &actual_compiled_class { + if let Some(CompiledClass::Class(_)) = &actual_compiled_class { actual_sierra_class.is_some() } else { actual_sierra_class.is_none() diff --git a/crates/katana/storage/provider/tests/contract.rs b/crates/katana/storage/provider/tests/contract.rs index 57a6f428fd..2e7e874263 100644 --- a/crates/katana/storage/provider/tests/contract.rs +++ b/crates/katana/storage/provider/tests/contract.rs @@ -5,7 +5,8 @@ use fixtures::{ db_provider, fork_provider_with_spawned_fork_network, in_memory_provider, provider_with_states, }; use katana_primitives::block::{BlockHashOrNumber, BlockNumber}; -use katana_primitives::contract::{ClassHash, ContractAddress, Nonce}; +use katana_primitives::class::ClassHash; +use katana_primitives::contract::{ContractAddress, Nonce}; use katana_provider::providers::fork::ForkedProvider; use katana_provider::providers::in_memory::InMemoryProvider; use katana_provider::traits::state::{StateFactoryProvider, StateProvider}; diff --git a/crates/katana/storage/provider/tests/fixtures.rs b/crates/katana/storage/provider/tests/fixtures.rs index fe5cf28f89..610fb6389d 100644 --- a/crates/katana/storage/provider/tests/fixtures.rs +++ b/crates/katana/storage/provider/tests/fixtures.rs @@ -5,9 +5,8 @@ use katana_db::mdbx; use katana_primitives::block::{ BlockHashOrNumber, FinalityStatus, Header, SealedBlock, SealedBlockWithStatus, SealedHeader, }; -use katana_primitives::contract::{ - CompiledContractClass, ContractAddress, FlattenedSierraClass, SierraClass, -}; +use katana_primitives::class::{CompiledClass, FlattenedSierraClass, SierraClass}; +use katana_primitives::contract::ContractAddress; use katana_primitives::genesis::constant::{ DEFAULT_LEGACY_ERC20_CONTRACT_CASM, DEFAULT_LEGACY_UDC_CASM, }; @@ -32,9 +31,12 @@ lazy_static! { let provider = runner.owned_provider(); (runner, Arc::new(provider)) }; - pub static ref DOJO_WORLD_COMPILED_CLASS: CompiledContractClass = - parse_compiled_class(include_str!("../../db/benches/artifacts/dojo_world_240.json")) - .unwrap(); + pub static ref DOJO_WORLD_COMPILED_CLASS: CompiledClass = { + let json = + serde_json::from_str(include_str!("../../db/benches/artifacts/dojo_world_240.json")) + .unwrap(); + parse_compiled_class(json).unwrap() + }; pub static ref DOJO_WORLD_SIERRA_CLASS: FlattenedSierraClass = { let sierra_class: SierraClass = serde_json::from_str(include_str!("../../db/benches/artifacts/dojo_world_240.json")) @@ -184,6 +186,7 @@ where }, state_update, Default::default(), + Default::default(), ) .unwrap(); } diff --git a/crates/katana/tasks/src/lib.rs b/crates/katana/tasks/src/lib.rs index 148630ade0..a51cee743f 100644 --- a/crates/katana/tasks/src/lib.rs +++ b/crates/katana/tasks/src/lib.rs @@ -64,7 +64,7 @@ impl TokioTaskSpawner { #[error("Failed to initialize blocking thread pool: {0}")] pub struct BlockingTaskPoolInitError(rayon::ThreadPoolBuildError); -type BlockingTaskResult = Result>; +pub type BlockingTaskResult = Result>; #[derive(Debug)] #[must_use = "BlockingTaskHandle does nothing unless polled"] @@ -76,7 +76,7 @@ impl Future for BlockingTaskHandle { fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { match Pin::new(&mut self.get_mut().0).poll(cx) { Poll::Ready(Ok(res)) => Poll::Ready(res), - Poll::Ready(Err(_)) => panic!("blocking task cancelled"), + Poll::Ready(Err(cancelled)) => Poll::Ready(Err(Box::new(cancelled))), Poll::Pending => Poll::Pending, } } diff --git a/crates/saya/core/Cargo.toml b/crates/saya/core/Cargo.toml index e30211361c..754df6d8ee 100644 --- a/crates/saya/core/Cargo.toml +++ b/crates/saya/core/Cargo.toml @@ -11,11 +11,13 @@ katana-db.workspace = true katana-executor.workspace = true katana-primitives.workspace = true katana-provider.workspace = true +katana-rpc-types.workspace = true +saya-provider.workspace = true anyhow.workspace = true async-trait.workspace = true convert_case.workspace = true -ethers = "2.0.11" +cairo-vm.workspace = true flate2.workspace = true futures.workspace = true lazy_static = "1.4.0" @@ -30,6 +32,7 @@ thiserror.workspace = true tokio.workspace = true tracing.workspace = true url.workspace = true +starknet-types-core = { version = "0.0.9", default-features = false, features = ["serde", "curve", "num-traits"] } # TODO: use features for each possible DA. celestia-rpc = "0.1.1" diff --git a/crates/saya/core/src/blockchain/mod.rs b/crates/saya/core/src/blockchain/mod.rs new file mode 100644 index 0000000000..0d301de6d4 --- /dev/null +++ b/crates/saya/core/src/blockchain/mod.rs @@ -0,0 +1,152 @@ +//! Blockchain fetched from Katana. +use std::collections::HashMap; + +use cairo_vm::vm::runners::builtin_runner::{ + BITWISE_BUILTIN_NAME, EC_OP_BUILTIN_NAME, HASH_BUILTIN_NAME, KECCAK_BUILTIN_NAME, + OUTPUT_BUILTIN_NAME, POSEIDON_BUILTIN_NAME, RANGE_CHECK_BUILTIN_NAME, + SEGMENT_ARENA_BUILTIN_NAME, SIGNATURE_BUILTIN_NAME, +}; +use katana_primitives::block::{BlockHashOrNumber, BlockIdOrTag, BlockTag, SealedBlockWithStatus}; +use katana_primitives::state::StateUpdatesWithDeclaredClasses; +use katana_provider::providers::in_memory::InMemoryProvider; +use katana_provider::traits::block::{BlockProvider, BlockWriter}; +use katana_provider::traits::contract::ContractClassWriter; +use katana_provider::traits::env::BlockEnvProvider; +use katana_provider::traits::state::{ + StateFactoryProvider, StateProvider, StateRootProvider, StateWriter, +}; +use katana_provider::traits::state_update::StateUpdateProvider; +use katana_provider::traits::transaction::{ + ReceiptProvider, TransactionProvider, TransactionStatusProvider, TransactionsProviderExt, +}; +use katana_provider::BlockchainProvider; + +use crate::error::{Error as SayaError, SayaResult}; + +pub trait Database: + BlockProvider + + BlockWriter + + TransactionProvider + + TransactionStatusProvider + + TransactionsProviderExt + + ReceiptProvider + + StateUpdateProvider + + StateRootProvider + + StateWriter + + ContractClassWriter + + StateFactoryProvider + + BlockEnvProvider + + 'static + + Send + + Sync +{ +} + +impl Database for T where + T: BlockProvider + + BlockWriter + + TransactionProvider + + TransactionStatusProvider + + TransactionsProviderExt + + ReceiptProvider + + StateUpdateProvider + + StateRootProvider + + StateWriter + + ContractClassWriter + + StateFactoryProvider + + BlockEnvProvider + + 'static + + Send + + Sync +{ +} + +/// Represents the whole blockchain fetched from Katana. +pub struct Blockchain { + inner: BlockchainProvider>, +} + +impl Default for Blockchain { + fn default() -> Self { + Self::new() + } +} + +impl Blockchain { + /// Initializes a new instance of [`Blockchain`]. + pub fn new() -> Self { + Self { inner: BlockchainProvider::new(Box::new(InMemoryProvider::new())) } + } + + /// Returns the internal provider. + pub fn provider(&self) -> &BlockchainProvider> { + &self.inner + } + + /// Retrieves historical state for the given block. + /// + /// # Arguments + /// + /// * `block_id` - The block id at which the state must be retrieved. + pub fn state(&self, block_id: &BlockIdOrTag) -> SayaResult> { + let provider = self.provider(); + + match block_id { + BlockIdOrTag::Tag(BlockTag::Latest) => { + let state = StateFactoryProvider::latest(provider)?; + Ok(state) + } + + BlockIdOrTag::Hash(hash) => { + StateFactoryProvider::historical(provider, BlockHashOrNumber::Hash(*hash))? + .ok_or(SayaError::BlockNotFound(*block_id)) + } + + BlockIdOrTag::Number(num) => { + StateFactoryProvider::historical(provider, BlockHashOrNumber::Num(*num))? + .ok_or(SayaError::BlockNotFound(*block_id)) + } + + BlockIdOrTag::Tag(BlockTag::Pending) => { + panic!("Pending block is not supported"); + } + } + } + + /// Updates the [`Blockchain`] internal state adding the given [`SealedBlockWithStatus`] + /// and the associated [`StateUpdatesWithDeclaredClasses`]. + /// + /// Currently receipts are ignored. + /// + /// # Arguments + /// + /// * `block` - The block to add. + /// * `states` - The state updates associated with the block. + pub fn update_state_with_block( + &mut self, + block: SealedBlockWithStatus, + states: StateUpdatesWithDeclaredClasses, + ) -> SayaResult<()> { + let provider = self.provider(); + // Receipts are not supported currently. We may need them if some + // information about the transaction is missing. + let receipts = vec![]; + + Ok(provider.insert_block_with_states_and_receipts(block, states, receipts, vec![])?) + } +} + +fn _get_default_vm_resource_fee_cost() -> HashMap { + HashMap::from([ + (String::from("n_steps"), 1_f64), + (HASH_BUILTIN_NAME.to_string(), 1_f64), + (RANGE_CHECK_BUILTIN_NAME.to_string(), 1_f64), + (SIGNATURE_BUILTIN_NAME.to_string(), 1_f64), + (BITWISE_BUILTIN_NAME.to_string(), 1_f64), + (POSEIDON_BUILTIN_NAME.to_string(), 1_f64), + (OUTPUT_BUILTIN_NAME.to_string(), 1_f64), + (EC_OP_BUILTIN_NAME.to_string(), 1_f64), + (KECCAK_BUILTIN_NAME.to_string(), 1_f64), + (SEGMENT_ARENA_BUILTIN_NAME.to_string(), 1_f64), + ]) +} diff --git a/crates/saya/core/src/data_availability/mod.rs b/crates/saya/core/src/data_availability/mod.rs index 356234a4c0..8bfe270cc6 100644 --- a/crates/saya/core/src/data_availability/mod.rs +++ b/crates/saya/core/src/data_availability/mod.rs @@ -12,7 +12,6 @@ use starknet::core::types::FieldElement; pub mod celestia; pub mod error; -pub mod state_diff; use error::DataAvailabilityResult; /// All possible chains configuration for data availability. diff --git a/crates/saya/core/src/error.rs b/crates/saya/core/src/error.rs index 1826aff786..aba773abd5 100644 --- a/crates/saya/core/src/error.rs +++ b/crates/saya/core/src/error.rs @@ -1,9 +1,19 @@ #[derive(thiserror::Error, Debug)] pub enum Error { + #[error(transparent)] + Anyhow(#[from] anyhow::Error), #[error(transparent)] DataAvailability(#[from] crate::data_availability::error::Error), #[error("Error from Katana client: {0}")] KatanaClient(String), + #[error(transparent)] + KatanaProvider(#[from] katana_provider::error::ProviderError), + #[error(transparent)] + SayaProvider(#[from] saya_provider::error::ProviderError), + #[error("Block {0:?} not found.")] + BlockNotFound(katana_primitives::block::BlockIdOrTag), + // #[error(transparent)] + // Snos(#[from] snos::error::SnOsError), } pub type SayaResult = Result; diff --git a/crates/saya/core/src/lib.rs b/crates/saya/core/src/lib.rs index ceb58eab2a..8d229b9294 100644 --- a/crates/saya/core/src/lib.rs +++ b/crates/saya/core/src/lib.rs @@ -1,19 +1,23 @@ //! Saya core library. + use std::sync::Arc; +use katana_primitives::block::{BlockNumber, FinalityStatus, SealedBlockWithStatus}; +use saya_provider::rpc::JsonRpcProvider; +use saya_provider::Provider as SayaProvider; use serde::{Deserialize, Serialize}; -use starknet::core::types::{BlockId, MaybePendingStateUpdate, StateUpdate}; -use starknet::providers::jsonrpc::HttpTransport; -use starknet::providers::{JsonRpcClient, Provider}; use tracing::{error, trace}; use url::Url; +use crate::blockchain::Blockchain; use crate::data_availability::{DataAvailabilityClient, DataAvailabilityConfig}; use crate::error::SayaResult; +pub mod blockchain; pub mod data_availability; pub mod error; pub mod prover; +pub mod starknet_os; pub mod verifier; /// Saya's main configuration. @@ -39,8 +43,10 @@ pub struct Saya { config: SayaConfig, /// The data availability client. da_client: Option>, - /// The katana (for now JSON RPC) client. - katana_client: Arc>, + /// The provider to fetch dojo from Katana. + provider: Arc, + /// The blockchain state. + blockchain: Blockchain, } impl Saya { @@ -50,8 +56,9 @@ impl Saya { /// /// * `config` - The main Saya configuration. pub async fn new(config: SayaConfig) -> SayaResult { - let katana_client = - Arc::new(JsonRpcClient::new(HttpTransport::new(config.katana_rpc.clone()))); + // Currently it's only RPC. But it can be the database + // file directly in the future or other transports. + let provider = Arc::new(JsonRpcProvider::new(config.katana_rpc.clone()).await?); let da_client = if let Some(da_conf) = &config.data_availability { Some(data_availability::client_from_config(da_conf.clone()).await?) @@ -59,7 +66,9 @@ impl Saya { None }; - Ok(Self { config, da_client, katana_client }) + let blockchain = Blockchain::new(); + + Ok(Self { config, da_client, provider, blockchain }) } /// Starts the Saya mainloop to fetch and process data. @@ -68,22 +77,22 @@ impl Saya { /// First naive version to have an overview of all the components /// and the process. /// Should be refacto in crates as necessary. - pub async fn start(&self) -> SayaResult<()> { + pub async fn start(&mut self) -> SayaResult<()> { let poll_interval_secs = 1; let mut block = self.config.start_block; loop { - let latest_block = match self.katana_client.block_number().await { + let latest_block = match self.provider.block_number().await { Ok(block_number) => block_number, Err(e) => { - error!("Can't retrieve latest block: {}", e); + error!(?e, "fetch block number"); tokio::time::sleep(tokio::time::Duration::from_secs(poll_interval_secs)).await; continue; } }; if block > latest_block { - trace!("Nothing to process yet, waiting for block {block}"); + trace!(block_number = block, "waiting block number"); tokio::time::sleep(tokio::time::Duration::from_secs(poll_interval_secs)).await; continue; } @@ -91,8 +100,6 @@ impl Saya { self.process_block(block).await?; block += 1; - - tokio::time::sleep(tokio::time::Duration::from_secs(poll_interval_secs)).await; } } @@ -114,38 +121,28 @@ impl Saya { /// # Arguments /// /// * `block_number` - The block number. - async fn process_block(&self, block_number: u64) -> SayaResult<()> { - trace!("Processing block {block_number}"); + async fn process_block(&mut self, block_number: BlockNumber) -> SayaResult<()> { + trace!(block_number, "processing block"); - self.fetch_publish_state_update(block_number).await?; + let block = self.provider.fetch_block(block_number).await?; + let (state_updates, da_state_update) = + self.provider.fetch_state_updates(block_number).await?; - Ok(()) - } + if let Some(da) = &self.da_client { + da.publish_state_diff_felts(&da_state_update).await?; + } - /// Fetches the state update for the given block and publish it to - /// the data availability layer (if any). - /// Returns the [`StateUpdate`]. - /// - /// # Arguments - /// - /// * `block_number` - The block number to get state update for. - async fn fetch_publish_state_update(&self, block_number: u64) -> SayaResult { - let state_update = - match self.katana_client.get_state_update(BlockId::Number(block_number)).await? { - MaybePendingStateUpdate::Update(su) => { - if let Some(da) = &self.da_client { - let sd_felts = - data_availability::state_diff::state_diff_to_felts(&su.state_diff); - - da.publish_state_diff_felts(&sd_felts).await?; - } - - su - } - MaybePendingStateUpdate::PendingUpdate(_) => unreachable!("Should not be used"), - }; + let block = SealedBlockWithStatus { block, status: FinalityStatus::AcceptedOnL2 }; + + self.blockchain.update_state_with_block(block.clone(), state_updates)?; - Ok(state_update) + if block_number == 0 { + return Ok(()); + } + + let _exec_infos = self.provider.fetch_transactions_executions(block_number).await?; + + Ok(()) } } diff --git a/crates/saya/core/src/starknet_os/felt.rs b/crates/saya/core/src/starknet_os/felt.rs new file mode 100644 index 0000000000..05199dddd2 --- /dev/null +++ b/crates/saya/core/src/starknet_os/felt.rs @@ -0,0 +1,25 @@ +//! Felt conversion. +//! +//! Starknet-rs should normally migrate to starknet types core. +//! To be removed once it's ok as the CairoVM is already using +//! the core types. +use starknet::core::types::FieldElement; +use starknet_types_core::felt::Felt; + +/// Converts a starknet-rs [`FieldElement`] to a starknet types core [`Felt`]. +/// +/// # Arguments +/// +/// * `ff` - Starknet-rs [`FieldElement`]. +pub fn from_ff(ff: &FieldElement) -> Felt { + Felt::from_bytes_be(&ff.to_bytes_be()) +} + +/// Converts a vec of [`FieldElement`] to a vec of starknet types core [`Felt`]. +/// +/// # Arguments +/// +/// * `ffs` - Starknet-rs [`&[FieldElement]`]. +pub fn from_ff_vec(ffs: &[FieldElement]) -> Vec { + ffs.iter().map(from_ff).collect() +} diff --git a/crates/saya/core/src/starknet_os/input.rs b/crates/saya/core/src/starknet_os/input.rs new file mode 100644 index 0000000000..5097f57c4e --- /dev/null +++ b/crates/saya/core/src/starknet_os/input.rs @@ -0,0 +1,23 @@ +//! Starknet OS inputs. +//! +//! Python code: +//! +use katana_primitives::block::SealedBlock; +use snos::io::input::StarknetOsInput; + +use super::{felt, transaction}; + +/// Setups a default [`StarknetOsInput`] with the block info. +/// +/// TODO: currently no commitments are computed, but are required +/// to be in the [`StarknetOsInput`]. +/// TODO: some of the input fields can be init from the state. +pub fn snos_input_from_block(block: &SealedBlock) -> StarknetOsInput { + let transactions = block.body.iter().map(transaction::snos_internal_from_tx).collect(); + + StarknetOsInput { + transactions, + block_hash: felt::from_ff(&block.header.hash), + ..Default::default() + } +} diff --git a/crates/saya/core/src/starknet_os/mod.rs b/crates/saya/core/src/starknet_os/mod.rs new file mode 100644 index 0000000000..de24233f11 --- /dev/null +++ b/crates/saya/core/src/starknet_os/mod.rs @@ -0,0 +1,8 @@ +//! Starknet OS types. +// SNOS is based on blockifier, which is not in sync with +// current primitives. +// And SNOS is for now not used. This work must be resume once +// SNOS is actualized. +// mod felt; +// pub mod input; +// pub mod transaction; diff --git a/crates/saya/core/src/starknet_os/transaction.rs b/crates/saya/core/src/starknet_os/transaction.rs new file mode 100644 index 0000000000..20600ce79b --- /dev/null +++ b/crates/saya/core/src/starknet_os/transaction.rs @@ -0,0 +1,120 @@ +//! Transaction conversion into Starknet OS internal transaction type. +//! +//! Transaction internal type python: +//! +//! Transaction types: +//! +use std::fmt; + +use katana_primitives::transaction::{DeclareTx, DeployAccountTx, InvokeTx, Tx, TxWithHash}; +use snos::io::InternalTransaction; +use starknet::core::types::FieldElement; + +use super::felt; + +pub fn snos_internal_from_tx(tx_with_hash: &TxWithHash) -> InternalTransaction { + let mut internal = + InternalTransaction { hash_value: felt::from_ff(&tx_with_hash.hash), ..Default::default() }; + + match &tx_with_hash.transaction { + Tx::Invoke(tx_e) => match tx_e { + InvokeTx::V1(tx) => { + internal.r#type = TransactionType::InvokeFunction.to_string(); + internal.entry_point_type = Some(EntryPointType::External.to_string()); + internal.version = Some(felt::from_ff(&FieldElement::ONE)); + internal.nonce = Some(felt::from_ff(&tx.nonce)); + internal.sender_address = Some(felt::from_ff(&tx.sender_address)); + internal.signature = Some(felt::from_ff_vec(&tx.signature)); + internal.calldata = Some(felt::from_ff_vec(&tx.calldata)); + // Entrypoint selector can be retrieved from Call? + } + // Will be done later as SNOS types should change. + _ => todo!(), + }, + Tx::Declare(tx_e) => match tx_e { + DeclareTx::V1(tx) => { + internal.r#type = TransactionType::Declare.to_string(); + internal.nonce = Some(felt::from_ff(&tx.nonce)); + internal.sender_address = Some(felt::from_ff(&tx.sender_address)); + internal.signature = Some(felt::from_ff_vec(&tx.signature)); + internal.class_hash = Some(felt::from_ff(&tx.class_hash)); + } + DeclareTx::V2(tx) => { + internal.r#type = TransactionType::Declare.to_string(); + internal.nonce = Some(felt::from_ff(&tx.nonce)); + internal.sender_address = Some(felt::from_ff(&tx.sender_address)); + internal.signature = Some(felt::from_ff_vec(&tx.signature)); + internal.class_hash = Some(felt::from_ff(&tx.class_hash)); + } + // Will be done later as SNOS types should change. + _ => todo!(), + }, + Tx::L1Handler(tx) => { + internal.r#type = TransactionType::L1Handler.to_string(); + internal.entry_point_type = Some(EntryPointType::L1Handler.to_string()); + internal.nonce = Some(felt::from_ff(&tx.nonce)); + internal.contract_address = Some(felt::from_ff(&tx.contract_address)); + internal.entry_point_selector = Some(felt::from_ff(&tx.entry_point_selector)); + internal.calldata = Some(felt::from_ff_vec(&tx.calldata)); + } + Tx::DeployAccount(tx_e) => match tx_e { + DeployAccountTx::V1(tx) => { + internal.r#type = TransactionType::DeployAccount.to_string(); + internal.nonce = Some(felt::from_ff(&tx.nonce)); + internal.contract_address = Some(felt::from_ff(&tx.contract_address)); + internal.contract_address_salt = Some(felt::from_ff(&tx.contract_address_salt)); + internal.class_hash = Some(felt::from_ff(&tx.class_hash)); + internal.constructor_calldata = Some(felt::from_ff_vec(&tx.constructor_calldata)); + internal.signature = Some(felt::from_ff_vec(&tx.signature)); + } + // Will be done later as SNOS types should change. + _ => todo!(), + }, + }; + + internal +} + +#[allow(dead_code)] +#[derive(Debug)] +enum TransactionType { + Declare, + Deploy, + DeployAccount, + InitializeBlockInfo, + InvokeFunction, + L1Handler, +} + +impl fmt::Display for TransactionType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match *self { + TransactionType::Declare => "DECLARE", + TransactionType::Deploy => "DEPLOY", + TransactionType::DeployAccount => "DEPLOY_ACCOUNT", + TransactionType::InitializeBlockInfo => "INITIALIZE_BLOCK_INFO", + TransactionType::InvokeFunction => "INVOKE_FUNCTION", + TransactionType::L1Handler => "L1_HANDLER", + }; + write!(f, "{}", s) + } +} + +#[allow(dead_code)] +#[derive(Debug)] +enum EntryPointType { + External, + L1Handler, + Constructor, +} + +impl fmt::Display for EntryPointType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match *self { + EntryPointType::External => "EXTERNAL", + EntryPointType::L1Handler => "L1_HANDLER", + EntryPointType::Constructor => "CONSTRUCTOR", + }; + write!(f, "{}", s) + } +} diff --git a/crates/saya/provider/Cargo.toml b/crates/saya/provider/Cargo.toml new file mode 100644 index 0000000000..13e9108e4a --- /dev/null +++ b/crates/saya/provider/Cargo.toml @@ -0,0 +1,34 @@ +[package] +description = "Saya providers to fetch block data from Katana." +edition.workspace = true +license-file.workspace = true +name = "saya-provider" +repository.workspace = true +version.workspace = true + +[dependencies] +katana-db.workspace = true +katana-executor.workspace = true +katana-primitives.workspace = true +katana-provider.workspace = true +katana-rpc-types.workspace = true +katana-rpc-api = { workspace = true, features = ["client"] } + +anyhow.workspace = true +auto_impl = "1.1.0" +async-trait.workspace = true +convert_case.workspace = true +ethers = "2.0.11" +flate2.workspace = true +futures.workspace = true +jsonrpsee = { workspace = true, features = ["client"] } +lazy_static = "1.4.0" +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +starknet.workspace = true +starknet_api.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing.workspace = true +url.workspace = true diff --git a/crates/saya/provider/src/error.rs b/crates/saya/provider/src/error.rs new file mode 100644 index 0000000000..df3074c664 --- /dev/null +++ b/crates/saya/provider/src/error.rs @@ -0,0 +1,16 @@ +//! Errors related to providers. + +/// Possible errors returned by the provider. +#[derive(Debug, thiserror::Error)] +pub enum ProviderError { + #[error(transparent)] + Anyhow(#[from] anyhow::Error), + #[error(transparent)] + KatanaProvider(#[from] katana_provider::error::ProviderError), + #[error("Block {0:?} not found.")] + BlockNotFound(katana_primitives::block::BlockIdOrTag), + #[error(transparent)] + StarknetProvider(#[from] starknet::providers::ProviderError), + #[error(transparent)] + ValueOutOfRange(#[from] starknet::core::types::ValueOutOfRangeError), +} diff --git a/crates/saya/provider/src/lib.rs b/crates/saya/provider/src/lib.rs new file mode 100644 index 0000000000..49aa867419 --- /dev/null +++ b/crates/saya/provider/src/lib.rs @@ -0,0 +1,13 @@ +//! Saya providers. +//! +//! A provider in Saya is responsible of fetching blocks data +//! and state updates from Katana. +pub mod error; +pub mod provider; +pub mod rpc; + +pub use provider::Provider; + +pub type ProviderResult = Result; + +const LOG_TARGET: &str = "provider"; diff --git a/crates/saya/provider/src/provider.rs b/crates/saya/provider/src/provider.rs new file mode 100644 index 0000000000..6401cdb798 --- /dev/null +++ b/crates/saya/provider/src/provider.rs @@ -0,0 +1,44 @@ +use katana_primitives::block::{BlockNumber, SealedBlock}; +use katana_primitives::state::StateUpdatesWithDeclaredClasses; +use katana_primitives::trace::TxExecInfo; +use starknet::core::types::FieldElement; + +use crate::ProviderResult; + +#[async_trait::async_trait] +#[auto_impl::auto_impl(&, Box, Arc)] +pub trait Provider { + /// Fetches the current block number of underlying chain. + async fn block_number(&self) -> ProviderResult; + + /// Fetches a block with it's transactions. + /// + /// # Arguments + /// + /// * `block_number` - The block to fetch. + async fn fetch_block(&self, block_number: BlockNumber) -> ProviderResult; + + /// Fetches the state updates related to a given block. + /// Returns the [`StateUpdatesWithDeclaredClasses`] and the serialiazed + /// state update for data availability layer. + /// + /// # Arguments + /// + /// * `block_number` - The block to fetch. + async fn fetch_state_updates( + &self, + block_number: BlockNumber, + ) -> ProviderResult<(StateUpdatesWithDeclaredClasses, Vec)>; + + /// Fetches the transactions executions info for a given block. + /// This method returns the all the executions info for each + /// transaction in a block. + /// + /// # Arguments + /// + /// * `block_number` - The block to fetch. + async fn fetch_transactions_executions( + &self, + block_number: BlockNumber, + ) -> ProviderResult>; +} diff --git a/crates/saya/provider/src/rpc/mod.rs b/crates/saya/provider/src/rpc/mod.rs new file mode 100644 index 0000000000..ffb0b93e64 --- /dev/null +++ b/crates/saya/provider/src/rpc/mod.rs @@ -0,0 +1,179 @@ +//! Provider to fetch Katana data from RPC. +//! +//! The transport here is fixed to JSON RPC. +use std::sync::Arc; + +use anyhow::anyhow; +use jsonrpsee::http_client::HttpClientBuilder; +use katana_primitives::block::{ + BlockIdOrTag, BlockNumber, GasPrices, Header, SealedBlock, SealedHeader, +}; +use katana_primitives::chain::ChainId; +use katana_primitives::conversion::rpc as rpc_converter; +use katana_primitives::state::StateUpdatesWithDeclaredClasses; +use katana_primitives::trace::TxExecInfo; +use katana_primitives::transaction::TxWithHash; +use katana_primitives::version::Version; +use katana_rpc_api::saya::SayaApiClient; +use katana_rpc_types::transaction::{TransactionsExecutionsPage, TransactionsPageCursor}; +use starknet::core::types::{ + ContractClass, FieldElement, MaybePendingBlockWithTxs, MaybePendingStateUpdate, +}; +use starknet::providers::jsonrpc::HttpTransport; +use starknet::providers::{JsonRpcClient, Provider as StarknetProvider}; +use tracing::trace; +use url::Url; + +use crate::provider::Provider; +use crate::rpc::{state as state_converter, transaction as tx_converter}; +use crate::{ProviderResult, LOG_TARGET}; + +mod state; +mod transaction; + +/// A JSON RPC provider. +pub struct JsonRpcProvider { + /// The RPC URL that must be kept for custom endpoints. + rpc_url: String, + /// The Starknet provider. + starknet_provider: Arc>, + /// Chain id detected from the `starknet_provider`. + chain_id: ChainId, +} + +impl JsonRpcProvider { + /// Initializes a new [`JsonRpcProvider`]. + /// Will attempt to fetch the chain id from the provider. + /// + /// # Arguments + /// + /// * `rpc_url` - The RPC url to fetch data from. Must be up and running to fetch the chain id. + pub async fn new(rpc_url: Url) -> ProviderResult { + let starknet_provider = Arc::new(JsonRpcClient::new(HttpTransport::new(rpc_url.clone()))); + + let chain_id: ChainId = starknet_provider.chain_id().await?.into(); + + Ok(Self { starknet_provider, chain_id, rpc_url: rpc_url.to_string() }) + } + + /// Returns the internal [`ChainId`]. + pub fn chain_id(&self) -> ChainId { + self.chain_id + } +} + +#[async_trait::async_trait] +impl Provider for JsonRpcProvider { + async fn block_number(&self) -> ProviderResult { + Ok(self.starknet_provider.block_number().await?) + } + + async fn fetch_block(&self, block_number: BlockNumber) -> ProviderResult { + let block = match self + .starknet_provider + .get_block_with_txs(BlockIdOrTag::Number(block_number)) + .await? + { + MaybePendingBlockWithTxs::Block(b) => b, + MaybePendingBlockWithTxs::PendingBlock(_) => { + panic!("PendingBlock should not be fetched") + } + }; + + let txs: Vec = block + .transactions + .iter() + .map(|tx_rpc| tx_converter::tx_from_rpc(tx_rpc, self.chain_id)) + .collect::, _>>()?; + + Ok(SealedBlock { + header: SealedHeader { + hash: block.block_hash, + header: Header { + parent_hash: block.parent_hash, + number: block.block_number, + gas_prices: GasPrices::new( + block.l1_gas_price.price_in_wei.try_into().unwrap(), + block.l1_gas_price.price_in_fri.try_into().unwrap(), + ), + timestamp: block.timestamp, + state_root: block.new_root, + sequencer_address: block.sequencer_address.into(), + version: Version::parse(&block.starknet_version)?, + }, + }, + body: txs, + }) + } + + async fn fetch_state_updates( + &self, + block_number: BlockNumber, + ) -> ProviderResult<(StateUpdatesWithDeclaredClasses, Vec)> { + let rpc_state_update = match self + .starknet_provider + .get_state_update(BlockIdOrTag::Number(block_number)) + .await? + { + MaybePendingStateUpdate::Update(su) => su, + MaybePendingStateUpdate::PendingUpdate(_) => { + return Err(anyhow!("PendingUpdate should not be fetched").into()); + } + }; + + let serialized_state_update = + state_converter::state_diff_to_felts(&rpc_state_update.state_diff); + let state_updates = state_converter::state_updates_from_rpc(&rpc_state_update)?; + + let mut state_updates_with_classes = + StateUpdatesWithDeclaredClasses { state_updates, ..Default::default() }; + + for class_hash in state_updates_with_classes.state_updates.declared_classes.keys() { + match self + .starknet_provider + .get_class(BlockIdOrTag::Number(block_number), class_hash) + .await? + { + ContractClass::Legacy(legacy) => { + trace!(target: LOG_TARGET, version = "cairo 0", %class_hash, "set contract class"); + + let (hash, class) = rpc_converter::legacy_rpc_to_compiled_class(&legacy)?; + state_updates_with_classes.declared_compiled_classes.insert(hash, class); + } + ContractClass::Sierra(s) => { + trace!(target: LOG_TARGET, version = "cairo 1", %class_hash, "set contract class"); + + state_updates_with_classes + .declared_sierra_classes + .insert(*class_hash, s.clone()); + } + } + } + + Ok((state_updates_with_classes, serialized_state_update)) + } + + async fn fetch_transactions_executions( + &self, + block_number: u64, + ) -> ProviderResult> { + trace!(target: LOG_TARGET, block_number, "fetch transactions executions"); + let cursor = TransactionsPageCursor { block_number, chunk_size: 50, ..Default::default() }; + + let client = HttpClientBuilder::default().build(&self.rpc_url).unwrap(); + let mut executions = vec![]; + + loop { + let rsp: TransactionsExecutionsPage = + client.get_transactions_executions(cursor).await.unwrap(); + + executions.extend(rsp.transactions_executions); + + if rsp.cursor.block_number > block_number { + break; + } + } + + Ok(executions) + } +} diff --git a/crates/saya/core/src/data_availability/state_diff.rs b/crates/saya/provider/src/rpc/state.rs similarity index 89% rename from crates/saya/core/src/data_availability/state_diff.rs rename to crates/saya/provider/src/rpc/state.rs index 7da386de05..890a88dd52 100644 --- a/crates/saya/core/src/data_availability/state_diff.rs +++ b/crates/saya/provider/src/rpc/state.rs @@ -1,7 +1,6 @@ -//! Formats the starknet state diff to be published -//! on a DA layer. +//! State update conversion and data availability formatting. //! -//! All the specification is available here: +//! For data availability format, all the specification is available here: //! . //! //! We use `U256` from ethers for easier computation (than working with felts). @@ -11,17 +10,61 @@ //! to know if an address has been deployed or declared. //! To avoid this overhead, we may want to first generate an hashmap of such //! arrays to then have O(1) search. -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use ethers::types::U256; +use katana_primitives::contract::ContractAddress; +use katana_primitives::state::StateUpdates; use starknet::core::types::{ ContractStorageDiffItem, DeclaredClassItem, DeployedContractItem, FieldElement, NonceUpdate, - StateDiff, + StateDiff, StateUpdate, }; +use crate::ProviderResult; + // 2 ^ 128 const CLASS_INFO_FLAG_TRUE: &str = "0x100000000000000000000000000000000"; +/// Converts the [`StateUpdate`] RPC type into [`StateUpdate`] Katana primitive. +/// +/// # Arguments +/// +/// * `state_update` - The RPC state update to convert. +pub fn state_updates_from_rpc(state_update: &StateUpdate) -> ProviderResult { + let mut out = StateUpdates::default(); + + let state_diff = &state_update.state_diff; + + for contract_diff in &state_diff.storage_diffs { + let ContractStorageDiffItem { address, storage_entries: entries } = contract_diff; + + let address: ContractAddress = (*address).into(); + + let contract_entry = out.storage_updates.entry(address).or_insert_with(HashMap::new); + + for e in entries { + contract_entry.insert(e.key, e.value); + } + } + + for nonce_update in &state_diff.nonces { + let NonceUpdate { contract_address, nonce: new_nonce } = *nonce_update; + out.nonce_updates.insert(contract_address.into(), new_nonce); + } + + for deployed in &state_diff.deployed_contracts { + let DeployedContractItem { address, class_hash } = *deployed; + out.contract_updates.insert(address.into(), class_hash); + } + + for decl in &state_diff.declared_classes { + let DeclaredClassItem { class_hash, compiled_class_hash } = decl; + out.declared_classes.insert(*class_hash, *compiled_class_hash); + } + + Ok(out) +} + /// Converts the [`StateDiff`] from RPC types into a [`Vec`]. /// /// Currently, Katana does not support `replaced_classes` and `deprecated_declared_classes`: diff --git a/crates/saya/provider/src/rpc/state_diff.rs b/crates/saya/provider/src/rpc/state_diff.rs new file mode 100644 index 0000000000..959eb414a1 --- /dev/null +++ b/crates/saya/provider/src/rpc/state_diff.rs @@ -0,0 +1,12 @@ + +use std::collections::HashSet; + +use ethers::types::U256; +use starknet::core::types::{ + ContractStorageDiffItem, DeclaredClassItem, DeployedContractItem, FieldElement, NonceUpdate, + StateDiff, +}; + +// 2 ^ 128 +const CLASS_INFO_FLAG_TRUE: &str = "0x100000000000000000000000000000000"; + diff --git a/crates/saya/provider/src/rpc/transaction.rs b/crates/saya/provider/src/rpc/transaction.rs new file mode 100644 index 0000000000..bbc39b316b --- /dev/null +++ b/crates/saya/provider/src/rpc/transaction.rs @@ -0,0 +1,164 @@ +//! Transactions related conversions. +use katana_primitives::chain::ChainId; +use katana_primitives::transaction::{ + DeclareTx, DeclareTxV1, DeclareTxV2, DeclareTxV3, DeployAccountTx, DeployAccountTxV1, + DeployAccountTxV3, InvokeTx, InvokeTxV1, InvokeTxV3, L1HandlerTx, Tx, TxWithHash, +}; +use starknet::core::types::{ + DeclareTransaction, DeployAccountTransaction, FieldElement, InvokeTransaction, Transaction, +}; + +use crate::ProviderResult; + +pub fn tx_from_rpc(tx_rpc: &Transaction, chain_id: ChainId) -> ProviderResult { + match tx_rpc { + Transaction::Invoke(tx_e) => match tx_e { + InvokeTransaction::V0(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: { + Tx::Invoke(InvokeTx::V1(InvokeTxV1 { + max_fee: tx.max_fee.try_into()?, + chain_id, + calldata: tx.calldata.clone(), + signature: tx.signature.clone(), + ..Default::default() + })) + }, + }), + InvokeTransaction::V1(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Invoke(InvokeTx::V1(InvokeTxV1 { + max_fee: tx.max_fee.try_into()?, + chain_id, + calldata: tx.calldata.clone(), + signature: tx.signature.clone(), + nonce: tx.nonce, + sender_address: tx.sender_address.into(), + })), + }), + InvokeTransaction::V3(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Invoke(InvokeTx::V3(InvokeTxV3 { + chain_id, + sender_address: tx.sender_address.into(), + nonce: tx.nonce, + calldata: tx.calldata.clone(), + signature: tx.signature.clone(), + resource_bounds: tx.resource_bounds.clone(), + tip: tx.tip, + paymaster_data: tx.paymaster_data.clone(), + account_deployment_data: tx.account_deployment_data.clone(), + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + })), + }), + }, + Transaction::L1Handler(tx) => { + // Seems we have data loss from only this content from the transaction. + // The receipt may be required to complete the data. + // (or use directly the database...) + Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::L1Handler(L1HandlerTx { + nonce: tx.nonce.into(), + chain_id, + version: FieldElement::ZERO, + calldata: tx.calldata.clone(), + contract_address: tx.contract_address.into(), + entry_point_selector: tx.entry_point_selector, + ..Default::default() + }), + }) + } + Transaction::Declare(tx_e) => match tx_e { + DeclareTransaction::V0(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Declare(DeclareTx::V1(DeclareTxV1 { + max_fee: tx.max_fee.try_into()?, + chain_id, + class_hash: tx.class_hash, + signature: tx.signature.clone(), + sender_address: tx.sender_address.into(), + ..Default::default() + })), + }), + DeclareTransaction::V1(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Declare(DeclareTx::V1(DeclareTxV1 { + nonce: tx.nonce, + max_fee: tx.max_fee.try_into()?, + chain_id, + class_hash: tx.class_hash, + signature: tx.signature.clone(), + sender_address: tx.sender_address.into(), + })), + }), + DeclareTransaction::V2(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Declare(DeclareTx::V2(DeclareTxV2 { + nonce: tx.nonce, + max_fee: tx.max_fee.try_into()?, + chain_id, + class_hash: tx.class_hash, + signature: tx.signature.clone(), + sender_address: tx.sender_address.into(), + compiled_class_hash: tx.compiled_class_hash, + })), + }), + DeclareTransaction::V3(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::Declare(DeclareTx::V3(DeclareTxV3 { + chain_id, + sender_address: tx.sender_address.into(), + nonce: tx.nonce, + signature: tx.signature.clone(), + class_hash: tx.class_hash, + compiled_class_hash: tx.compiled_class_hash, + resource_bounds: tx.resource_bounds.clone(), + tip: tx.tip, + paymaster_data: tx.paymaster_data.clone(), + account_deployment_data: tx.account_deployment_data.clone(), + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + })), + }), + }, + Transaction::DeployAccount(tx_e) => match tx_e { + DeployAccountTransaction::V1(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::DeployAccount(DeployAccountTx::V1(DeployAccountTxV1 { + nonce: tx.nonce, + max_fee: tx.max_fee.try_into()?, + chain_id, + class_hash: tx.class_hash, + signature: tx.signature.clone(), + contract_address_salt: tx.contract_address_salt, + constructor_calldata: tx.constructor_calldata.clone(), + // contract_address field is missing in tx, to be checked. + ..Default::default() + })), + }), + DeployAccountTransaction::V3(tx) => Ok(TxWithHash { + hash: tx.transaction_hash, + transaction: Tx::DeployAccount(DeployAccountTx::V3(DeployAccountTxV3 { + chain_id, + nonce: tx.nonce, + signature: tx.signature.clone(), + class_hash: tx.class_hash, + // contract_address field is missing in tx, to be checked. + contract_address: Default::default(), + contract_address_salt: tx.contract_address_salt, + constructor_calldata: tx.constructor_calldata.clone(), + resource_bounds: tx.resource_bounds.clone(), + tip: tx.tip, + paymaster_data: tx.paymaster_data.clone(), + nonce_data_availability_mode: tx.nonce_data_availability_mode, + fee_data_availability_mode: tx.fee_data_availability_mode, + })), + }), + }, + Transaction::Deploy(_) => { + panic!("Deploy transaction not supported"); + } + } +} diff --git a/scripts/clippy.sh b/scripts/clippy.sh index 8c01e87ecb..a3ec765c8c 100755 --- a/scripts/clippy.sh +++ b/scripts/clippy.sh @@ -1,7 +1,11 @@ #!/bin/bash run_clippy() { - cargo clippy --all-targets --all-features "$@" -- -D warnings -D future-incompatible -D nonstandard-style -D rust-2018-idioms -D unused + cargo clippy --all-targets "$@" -- -D warnings -D future-incompatible -D nonstandard-style -D rust-2018-idioms -D unused } -run_clippy +run_clippy --all-features --workspace --exclude katana --exclude katana-executor + +run_clippy -p katana-executor --all +run_clippy -p katana +run_clippy -p katana --no-default-features --features sir diff --git a/scripts/docs.sh b/scripts/docs.sh index a0e973eb3d..1d6440fc5e 100755 --- a/scripts/docs.sh +++ b/scripts/docs.sh @@ -1,3 +1,4 @@ #!/bin/bash -RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items --no-deps --all-features +RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items --no-deps --all-features --workspace --exclude katana +RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items --no-deps -p katana