diff --git a/Cargo.lock b/Cargo.lock index e9e5d67840..8d6a907a1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1410,7 +1410,7 @@ dependencies = [ "num-integer", "num-traits 0.2.17", "smol_str", - "starknet-crypto 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-crypto 0.6.1", "thiserror", ] @@ -1594,7 +1594,7 @@ dependencies = [ "serde_json", "sha3", "smol_str", - "starknet-crypto 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-crypto 0.6.1", "thiserror", ] @@ -1669,7 +1669,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sha3", - "starknet-crypto 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-crypto 0.6.1", "thiserror-no-std", ] @@ -2579,7 +2579,7 @@ dependencies = [ "rstest 0.18.2", "serde", "serde_json", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", "starknet-providers", "starknet-rpc-test", "thiserror", @@ -6224,7 +6224,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "starknet-core", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", "starknet_api", "substrate-wasm-builder", ] @@ -6247,8 +6247,8 @@ dependencies = [ "starknet-accounts", "starknet-contract", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-rpc-test", "starknet-signers", @@ -6480,6 +6480,7 @@ version = "0.7.0" dependencies = [ "anyhow", "blockifier", + "cairo-vm", "frame-support", "frame-system", "hex", @@ -6514,7 +6515,7 @@ dependencies = [ "sp-runtime 24.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "sp-timestamp", "starknet-core", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", "starknet_api", "thiserror", "tokio", @@ -6590,7 +6591,7 @@ dependencies = [ "sp-io 23.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "sp-runtime 24.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "starknet-core-contract-client", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", "starknet_api", "thiserror", "url", @@ -6819,7 +6820,7 @@ name = "mp-chain-id" version = "0.7.0" dependencies = [ "mp-felt", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", ] [[package]] @@ -6853,7 +6854,7 @@ dependencies = [ "serde_with", "sp-core 21.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "starknet-core", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", "starknet_api", "thiserror-no-std", ] @@ -6870,7 +6871,7 @@ dependencies = [ "serde_json", "serde_with", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", ] [[package]] @@ -6882,7 +6883,7 @@ dependencies = [ "scale-info", "serde", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", ] [[package]] @@ -6903,7 +6904,7 @@ name = "mp-program-hash" version = "0.7.0" dependencies = [ "mp-felt", - "starknet-ff 0.3.5", + "starknet-ff 0.3.7", ] [[package]] @@ -6990,9 +6991,11 @@ dependencies = [ "scale-info", "serde", "serde_json", + "sha3", + "sp-core 21.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet_api", "thiserror", ] @@ -7729,8 +7732,8 @@ dependencies = [ "sp-runtime 24.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "sp-std 8.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet_api", "test-case", ] @@ -12135,8 +12138,8 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "starknet-accounts" -version = "0.6.1" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.9.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "async-trait", "auto_impl", @@ -12148,8 +12151,8 @@ dependencies = [ [[package]] name = "starknet-contract" -version = "0.6.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.9.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "serde", "serde_json", @@ -12162,8 +12165,8 @@ dependencies = [ [[package]] name = "starknet-core" -version = "0.7.2" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "base64 0.21.5", "flate2", @@ -12173,8 +12176,8 @@ dependencies = [ "serde_json_pythonic", "serde_with", "sha3", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", ] [[package]] @@ -12203,7 +12206,7 @@ dependencies = [ "num-traits 0.2.17", "rfc6979", "sha2 0.10.8", - "starknet-crypto-codegen 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-crypto-codegen 0.3.2", "starknet-curve 0.3.0", "starknet-ff 0.3.6", "zeroize", @@ -12223,7 +12226,7 @@ dependencies = [ "num-traits 0.2.17", "rfc6979", "sha2 0.10.8", - "starknet-crypto-codegen 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "starknet-crypto-codegen 0.3.2", "starknet-curve 0.4.1", "starknet-ff 0.3.6", "zeroize", @@ -12231,8 +12234,8 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.6.1" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.6.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "crypto-bigint", "hex", @@ -12242,9 +12245,9 @@ dependencies = [ "num-traits 0.2.17", "rfc6979", "sha2 0.10.8", - "starknet-crypto-codegen 0.3.2 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-curve 0.4.0", - "starknet-ff 0.3.5", + "starknet-crypto-codegen 0.3.3", + "starknet-curve 0.4.2", + "starknet-ff 0.3.7", "zeroize", ] @@ -12261,11 +12264,11 @@ dependencies = [ [[package]] name = "starknet-crypto-codegen" -version = "0.3.2" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.3.3" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ - "starknet-curve 0.4.0", - "starknet-ff 0.3.5", + "starknet-curve 0.4.2", + "starknet-ff 0.3.7", "syn 2.0.48", ] @@ -12280,19 +12283,19 @@ dependencies = [ [[package]] name = "starknet-curve" -version = "0.4.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" dependencies = [ - "starknet-ff 0.3.5", + "starknet-ff 0.3.6", ] [[package]] name = "starknet-curve" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" +version = "0.4.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ - "starknet-ff 0.3.6", + "starknet-ff 0.3.7", ] [[package]] @@ -12321,8 +12324,8 @@ dependencies = [ "starknet-contract", "starknet-core", "starknet-core-contract-client", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-signers", "starknet_api", @@ -12334,33 +12337,33 @@ dependencies = [ [[package]] name = "starknet-ff" -version = "0.3.5" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067419451efdea1ee968df8438369960c167e0e905c05b84afd074f50e1d6f3d" dependencies = [ "ark-ff 0.4.2", - "bigdecimal", "crypto-bigint", "getrandom 0.2.11", "hex", - "serde", ] [[package]] name = "starknet-ff" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "067419451efdea1ee968df8438369960c167e0e905c05b84afd074f50e1d6f3d" +version = "0.3.7" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "ark-ff 0.4.2", + "bigdecimal", "crypto-bigint", "getrandom 0.2.11", "hex", + "serde", ] [[package]] name = "starknet-providers" -version = "0.7.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.10.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "async-trait", "auto_impl", @@ -12392,8 +12395,8 @@ dependencies = [ "starknet-accounts", "starknet-contract", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-signers", "thiserror", @@ -12403,8 +12406,8 @@ dependencies = [ [[package]] name = "starknet-signers" -version = "0.5.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.8.0" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ "async-trait", "auto_impl", @@ -12412,7 +12415,7 @@ dependencies = [ "eth-keystore", "rand 0.8.5", "starknet-core", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 6e19d7dbe9..1272696941 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -265,19 +265,19 @@ cairo-vm = { git = "https://github.com/bidzyyys/cairo-vm", branch = "feature/sca "cairo-1-hints", "parity-scale-codec", ] } -starknet-crypto = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false, features = [ +starknet-crypto = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false, features = [ "std", ] } -starknet-core = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false, features = [ +starknet-core = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false, features = [ "std", ] } -starknet-providers = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false } -starknet-ff = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false, features = [ +starknet-providers = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false } +starknet-ff = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false, features = [ "std", ] } -starknet-signers = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false } -starknet-accounts = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false } -starknet-contract = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "64ebc36", default-features = false } +starknet-signers = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false } +starknet-accounts = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false } +starknet-contract = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", default-features = false } blockifier = { git = "https://github.com/bidzyyys/blockifier", branch = "feature/scale-codec"} starknet_api = { git = "https://github.com/bidzyyys/starknet-api", branch = "feature/scale-codec", features = [ diff --git a/crates/client/db/src/mapping_db.rs b/crates/client/db/src/mapping_db.rs index 5b8afcbdb3..ca3c4ed163 100644 --- a/crates/client/db/src/mapping_db.rs +++ b/crates/client/db/src/mapping_db.rs @@ -5,7 +5,9 @@ use std::sync::{Arc, Mutex}; use parity_scale_codec::{Decode, Encode}; use sp_database::Database; use sp_runtime::traits::Block as BlockT; +use starknet_api::block::BlockHash; use starknet_api::hash::StarkHash; +use starknet_api::transaction::TransactionHash; use crate::{DbError, DbHash}; @@ -13,8 +15,8 @@ use crate::{DbError, DbHash}; #[derive(Debug)] pub struct MappingCommitment { pub block_hash: B::Hash, - pub starknet_block_hash: StarkHash, - pub starknet_transaction_hashes: Vec, + pub starknet_block_hash: BlockHash, + pub starknet_transaction_hashes: Vec, } /// Allow interaction with the mapping db @@ -44,7 +46,7 @@ impl MappingDb { /// /// Under some circumstances it can return multiples blocks hashes, meaning that the result has /// to be checked against the actual blockchain state in order to find the good one. - pub fn block_hash(&self, starknet_block_hash: StarkHash) -> Result>, DbError> { + pub fn block_hash(&self, starknet_block_hash: BlockHash) -> Result>, DbError> { match self.db.get(crate::columns::BLOCK_MAPPING, &starknet_block_hash.encode()) { Some(raw) => Ok(Some(Vec::::decode(&mut &raw[..])?)), None => Ok(None), @@ -121,7 +123,10 @@ impl MappingDb { /// * `transaction_hash` - the transaction hash to search for. H256 is used here because it's a /// native type of substrate, and we are sure it's SCALE encoding is optimized and will not /// change. - pub fn block_hash_from_transaction_hash(&self, transaction_hash: StarkHash) -> Result, DbError> { + pub fn block_hash_from_transaction_hash( + &self, + transaction_hash: TransactionHash, + ) -> Result, DbError> { match self.db.get(crate::columns::TRANSACTION_MAPPING, &transaction_hash.encode()) { Some(raw) => Ok(Some(::decode(&mut &raw[..])?)), None => Ok(None), @@ -144,7 +149,7 @@ impl MappingDb { /// - The provided `starknet_hash` is not present in the cache. pub fn cached_transaction_hashes_from_block_hash( &self, - starknet_block_hash: StarkHash, + starknet_block_hash: BlockHash, ) -> Result>, DbError> { if !self.cache_more_things { // The cache is not enabled, no need to even touch the database. diff --git a/crates/client/l1-messages/src/worker.rs b/crates/client/l1-messages/src/worker.rs index d46a0d01d9..d5164175e6 100644 --- a/crates/client/l1-messages/src/worker.rs +++ b/crates/client/l1-messages/src/worker.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use ethers::providers::{Http, Provider, StreamExt}; use ethers::types::U256; pub use mc_eth_client::config::EthereumClientConfig; -use mp_hashers::HasherT; use mp_transactions::compute_hash::ComputeTransactionHash; use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi}; use sc_client_api::HeaderBackend; @@ -26,7 +25,7 @@ fn create_event_listener( Ok(StarknetMessagingEvents::new(address, Arc::new(provider))) } -pub async fn run_worker( +pub async fn run_worker( config: EthereumClientConfig, client: Arc, pool: Arc

, @@ -36,7 +35,6 @@ pub async fn run_worker( C: ProvideRuntimeApi + HeaderBackend, C::Api: StarknetRuntimeApi + ConvertTransactionRuntimeApi, P: TransactionPool + 'static, - H: HasherT + Send + Sync + 'static, { log::info!("⟠ Starting L1 Messages Worker with settings: {:?}", config); @@ -74,7 +72,7 @@ pub async fn run_worker( meta.log_index ); - match process_l1_message::<_, _, _, _, H>( + match process_l1_message::<_, _, _, _>( event, &client, &pool, @@ -110,7 +108,7 @@ pub async fn run_worker( } } -async fn process_l1_message( +async fn process_l1_message( event: LogMessageToL2Filter, client: &Arc, pool: &Arc

, @@ -124,7 +122,6 @@ where C::Api: StarknetRuntimeApi + ConvertTransactionRuntimeApi, P: TransactionPool + 'static, PE: std::error::Error, - H: HasherT + Send + Sync + 'static, { // Check against panic // https://docs.rs/ethers/latest/ethers/types/struct.U256.html#method.as_u128 @@ -152,7 +149,7 @@ where let chain_id = client.runtime_api().chain_id(best_block_hash).map_err(|e| L1MessagesWorkerError::RuntimeApiError(e.into()))?; // TODO: Find a way not to hardcode that - let tx_hash = tx.compute_hash::(chain_id, false); + let tx_hash = tx.compute_hash(chain_id, false); let transaction = blockifier::transaction::transactions::L1HandlerTransaction { tx, tx_hash, paid_fee_on_l1 }; let extrinsic = client.runtime_api().convert_l1_transaction(best_block_hash, transaction).map_err(|e| { diff --git a/crates/client/mapping-sync/src/sync_blocks.rs b/crates/client/mapping-sync/src/sync_blocks.rs index 41ffb34681..b21bd859b2 100644 --- a/crates/client/mapping-sync/src/sync_blocks.rs +++ b/crates/client/mapping-sync/src/sync_blocks.rs @@ -1,8 +1,10 @@ -use blockifier::transaction_execution::Transaction; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::transaction_execution::Transaction; use mc_rpc_core::utils::get_block_by_block_hash; use mp_digest_log::{find_starknet_block, FindLogError}; use mp_hashers::HasherT; use mp_transactions::compute_hash::ComputeTransactionHash; +use mp_transactions::get_transaction_hash; use pallet_starknet_runtime_api::StarknetRuntimeApi; use sc_client_api::backend::{Backend, StorageProvider}; use sp_api::ProvideRuntimeApi; @@ -37,8 +39,6 @@ where db state ({storage_starknet_block_hash:?})" )) } else { - let chain_id = client.runtime_api().chain_id(substrate_block_hash)?; - // Success, we write the Starknet to Substate hashes mapping to db let mapping_commitment = mc_db::MappingCommitment { block_hash: substrate_block_hash, @@ -46,10 +46,8 @@ where starknet_transaction_hashes: digest_starknet_block .transactions() .iter() - .map(|tx| match tx { - Transaction::AccountTransaction(tx) => tx.tx_hash(), - Transaction::L1HandlerTransacton(tx) => tx.tx_hash, - }) + .map(get_transaction_hash) + .cloned() .collect(), }; diff --git a/crates/client/rpc-core/src/utils.rs b/crates/client/rpc-core/src/utils.rs index 950f784a14..df3291c9ec 100644 --- a/crates/client/rpc-core/src/utils.rs +++ b/crates/client/rpc-core/src/utils.rs @@ -319,8 +319,10 @@ pub fn casm_contract_class_to_compiled_class(casm_contract_class: &CasmContractC compiler_version: casm_contract_class.compiler_version.clone(), bytecode: casm_contract_class.bytecode.iter().map(|x| biguint_to_field_element(&x.value)).collect(), entry_points_by_type: casm_entry_points_to_compiled_entry_points(&casm_contract_class.entry_points_by_type), - hints: vec![], // not needed to get class hash so ignoring this - pythonic_hints: None, // not needed to get class hash so ignoring this + // TODO: fill those + hints: vec![], + pythonic_hints: None, + bytecode_segment_lengths: vec![], } } diff --git a/crates/client/rpc/Cargo.toml b/crates/client/rpc/Cargo.toml index 47ba28b4b5..69ef97f936 100644 --- a/crates/client/rpc/Cargo.toml +++ b/crates/client/rpc/Cargo.toml @@ -65,6 +65,7 @@ mp-transactions = { workspace = true, features = ["client"] } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } tokio = { workspace = true, default-features = true, features = ["time"] } +cairo-vm = { workspace = true, default-features = true } [dev-dependencies] rstest = { workspace = true } diff --git a/crates/client/rpc/src/events/mod.rs b/crates/client/rpc/src/events/mod.rs index 5c84db767c..25a86fcea5 100644 --- a/crates/client/rpc/src/events/mod.rs +++ b/crates/client/rpc/src/events/mod.rs @@ -9,7 +9,6 @@ use log::error; use mc_rpc_core::utils::get_block_by_block_hash; use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; -use mp_transactions::compute_hash::ComputeTransactionHash; use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi}; use sc_client_api::backend::{Backend, StorageProvider}; use sc_client_api::BlockBackend; @@ -17,7 +16,6 @@ use sc_transaction_pool::ChainApi; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; -use starknet_api::transaction::TransactionHash; use starknet_core::types::{BlockId, EmittedEvent, EventsPage}; use starknet_ff::FieldElement; @@ -63,29 +61,22 @@ where error!("Failed to retrieve starknet block from substrate block hash: error: {e}"); StarknetRpcApiError::InternalServerError })?; - let txn_hashes = - if let Some(tx_hashes) = self.get_cached_transaction_hashes(starknet_block.header().hash::().into()) { - tx_hashes - } else { - starknet_block.transactions().iter().map(|tx| tx.compute_hash::(chain_id, false).into()).collect() - }; let block_hash = starknet_block.header().hash::(); let mut emitted_events: Vec = vec![]; - for tx_hash in txn_hashes { - let raw_events = - runtime_api.get_events_for_tx_by_hash(substrate_block_hash, TransactionHash(tx_hash)).map_err(|e| { - error!("Failed to retrieve starknet events for transaction: error: {e}"); - StarknetRpcApiError::InternalServerError - })?; + for tx_hash in starknet_block.transactions_hashes() { + let raw_events = runtime_api.get_events_for_tx_by_hash(substrate_block_hash, tx_hash).map_err(|e| { + error!("Failed to retrieve starknet events for transaction: error: {e}"); + StarknetRpcApiError::InternalServerError + })?; for event in raw_events { emitted_events.push(EmittedEvent { from_address: Felt252Wrapper::from(event.from_address).0, keys: event.content.keys.into_iter().map(|felt| Felt252Wrapper::from(felt).0).collect(), data: event.content.data.0.into_iter().map(|felt| Felt252Wrapper::from(felt).0).collect(), - block_hash: block_hash.0, - block_number, + block_hash: Some(block_hash.into()), + block_number: Some(block_number), transaction_hash: Felt252Wrapper::from(tx_hash).0, }) } diff --git a/crates/client/rpc/src/lib.rs b/crates/client/rpc/src/lib.rs index fcc874d504..5d6cce0059 100644 --- a/crates/client/rpc/src/lib.rs +++ b/crates/client/rpc/src/lib.rs @@ -15,7 +15,9 @@ use std::collections::HashMap; use std::marker::PhantomData; use std::sync::Arc; +use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::objects::ResourcesMapping; +use blockifier::transaction::transactions::L1HandlerTransaction; use errors::StarknetRpcApiError; use jsonrpsee::core::{async_trait, RpcResult}; use jsonrpsee::types::error::CallError; @@ -28,10 +30,15 @@ pub use mc_rpc_core::{ }; use mc_storage::OverrideHandle; use mp_felt::Felt252Wrapper; +use mp_hashers::pedersen::PedersenHasher; use mp_hashers::HasherT; use mp_transactions::compute_hash::ComputeTransactionHash; +use mp_transactions::from_broadcasted_transactions::{ + try_account_tx_from_broadcasted_declare_tx, try_account_tx_from_broadcasted_deploy_tx, + try_account_tx_from_broadcasted_invoke_tx, try_account_tx_from_broadcasted_tx, +}; use mp_transactions::to_starknet_core_transaction::to_starknet_core_tx; -use mp_transactions::{TransactionStatus, UserTransaction}; +use mp_transactions::{compute_message_hash, get_account_transaction_hash, get_transaction_hash, TransactionStatus}; use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi}; use sc_client_api::backend::{Backend, StorageProvider}; use sc_client_api::BlockBackend; @@ -47,19 +54,21 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::transaction_validity::InvalidTransaction; use sp_runtime::DispatchError; use starknet_api::block::BlockHash; -use starknet_api::hash::StarkHash; -use starknet_api::transaction::{Calldata, TransactionHash}; +use starknet_api::core::Nonce; +use starknet_api::hash::{StarkFelt, StarkHash}; +use starknet_api::transaction::{Calldata, Fee, TransactionHash, TransactionVersion}; use starknet_core::types::{ BlockHashAndNumber, BlockId, BlockStatus, BlockTag, BlockWithTxHashes, BlockWithTxs, BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, ContractClass, DeclareTransactionReceipt, DeclareTransactionResult, DeployAccountTransactionReceipt, DeployAccountTransactionResult, EventFilterWithPage, EventsPage, ExecutionResources, ExecutionResult, FeeEstimate, - FieldElement, FunctionCall, Hash256, InvokeTransactionReceipt, InvokeTransactionResult, + FeePayment, FieldElement, FunctionCall, Hash256, InvokeTransactionReceipt, InvokeTransactionResult, L1HandlerTransactionReceipt, MaybePendingBlockWithTxHashes, MaybePendingBlockWithTxs, MaybePendingStateUpdate, MaybePendingTransactionReceipt, MsgFromL1, PendingBlockWithTxHashes, PendingBlockWithTxs, PendingDeclareTransactionReceipt, PendingDeployAccountTransactionReceipt, PendingInvokeTransactionReceipt, - PendingL1HandlerTransactionReceipt, PendingStateUpdate, PendingTransactionReceipt, StateDiff, StateUpdate, - SyncStatus, SyncStatusType, Transaction, TransactionExecutionStatus, TransactionFinalityStatus, TransactionReceipt, + PendingL1HandlerTransactionReceipt, PendingStateUpdate, PendingTransactionReceipt, PriceUnit, StateDiff, + StateUpdate, SyncStatus, SyncStatusType, Transaction, TransactionExecutionStatus, TransactionFinalityStatus, + TransactionReceipt, }; use starknet_core::utils::get_selector_from_name; @@ -199,18 +208,6 @@ where Ok(starknet_block.header().block_number) } - /// Returns a list of all transaction hashes in the given block. - /// - /// # Arguments - /// - /// * `block_hash` - The hash of the block containing the transactions (starknet block). - fn get_cached_transaction_hashes(&self, block_hash: StarkHash) -> Option> { - self.backend.mapping().cached_transaction_hashes_from_block_hash(block_hash).unwrap_or_else(|err| { - error!("Failed to read from cache: {err}"); - None - }) - } - /// Returns the state diff for the given block. /// /// # Arguments @@ -226,36 +223,6 @@ where Ok(rpc_state_diff) } - - fn try_txn_hash_from_cache( - &self, - tx_index: usize, - cached_transactions: &Option>, - transactions: &[mp_transactions::Transaction], - chain_id: Felt252Wrapper, - ) -> Result { - if let Some(txn_hashes) = &cached_transactions { - let txn_hash = (&txn_hashes - .get(tx_index) - .ok_or_else(|| { - error!("Failed to retrieve transaction hash from cache, invalid index {}", tx_index); - StarknetRpcApiError::InternalServerError - })? - .0) - .try_into() - .map_err(|_| { - error!("Failed to convert transaction hash"); - StarknetRpcApiError::InternalServerError - })?; - Ok(txn_hash) - } else { - let transaction = &transactions.get(tx_index).ok_or_else(|| { - error!("Failed to retrieve transaction hash from starknet txs, invalid index {}", tx_index); - StarknetRpcApiError::InternalServerError - })?; - Ok(transaction.compute_hash::(chain_id, false)) - } - } } /// Taken from https://github.com/paritytech/substrate/blob/master/client/rpc/src/author/mod.rs#L78 @@ -336,12 +303,15 @@ where None }; - let transaction: UserTransaction = declare_transaction.try_into().map_err(|e| { - error!("Failed to convert BroadcastedDeclareTransaction to UserTransaction, error: {e}"); - StarknetRpcApiError::InternalServerError - })?; - let class_hash = match transaction { - UserTransaction::Declare(ref tx, _) => tx.class_hash(), + let chain_id = Felt252Wrapper(self.chain_id()?.0); + + let transaction: AccountTransaction = try_account_tx_from_broadcasted_declare_tx(declare_transaction, chain_id) + .map_err(|e| { + error!("Failed to convert BroadcastedDeclareTransaction to AccountTransaction, error: {e}"); + StarknetRpcApiError::InternalServerError + })?; + let (class_hash, tx_hash) = match &transaction { + AccountTransaction::Declare(tx) => (tx.class_hash(), tx.tx_hash()), _ => Err(StarknetRpcApiError::InternalServerError)?, }; @@ -349,7 +319,7 @@ where let contract_class = self .overrides .for_block_hash(self.client.as_ref(), current_block_hash) - .contract_class_by_class_hash(current_block_hash, (*class_hash).into()); + .contract_class_by_class_hash(current_block_hash, class_hash); if let Some(contract_class) = contract_class { error!("Contract class already exists: {:?}", contract_class); @@ -360,22 +330,16 @@ where submit_extrinsic(self.pool.clone(), best_block_hash, extrinsic).await?; - let chain_id = Felt252Wrapper(self.chain_id()?.0); - - let tx_hash = transaction.compute_hash::(chain_id, false).into(); - if let Some(sierra_contract_class) = opt_sierra_contract_class { - if let Some(e) = self - .backend - .sierra_classes() - .store_sierra_class(Felt252Wrapper::from(class_hash.0).into(), sierra_contract_class) - .err() - { - log::error!("Failed to store the sierra contract class for declare tx `{tx_hash:x}`: {e}") + if let Some(e) = self.backend.sierra_classes().store_sierra_class(class_hash, sierra_contract_class).err() { + log::error!("Failed to store the sierra contract class for declare tx `{tx_hash}`: {e}") } } - Ok(DeclareTransactionResult { transaction_hash: tx_hash, class_hash: class_hash.0 }) + Ok(DeclareTransactionResult { + transaction_hash: Felt252Wrapper::from(tx_hash).into(), + class_hash: Felt252Wrapper::from(class_hash).into(), + }) } /// Add an Invoke Transaction to invoke a contract function @@ -392,19 +356,20 @@ where invoke_transaction: BroadcastedInvokeTransaction, ) -> RpcResult { let best_block_hash = self.get_best_block_hash(); + let chain_id = Felt252Wrapper(self.chain_id()?.0); - let transaction: UserTransaction = invoke_transaction.try_into().map_err(|e| { - error!("Failed to convert BroadcastedInvokeTransaction to UserTransaction: {e}"); + let transaction: AccountTransaction = try_account_tx_from_broadcasted_invoke_tx(invoke_transaction, chain_id) + .map_err(|e| { + error!("Failed to convert BroadcastedInvokeTransaction to AccountTransaction: {e}"); StarknetRpcApiError::InternalServerError })?; + let tx_hash = get_account_transaction_hash(&transaction); let extrinsic = self.convert_tx_to_extrinsic(best_block_hash, transaction.clone())?; submit_extrinsic(self.pool.clone(), best_block_hash, extrinsic).await?; - let chain_id = Felt252Wrapper(self.chain_id()?.0); - - Ok(InvokeTransactionResult { transaction_hash: transaction.compute_hash::(chain_id, false).into() }) + Ok(InvokeTransactionResult { transaction_hash: Felt252Wrapper::from(*tx_hash).into() }) } /// Add an Deploy Account Transaction @@ -422,25 +387,26 @@ where deploy_account_transaction: BroadcastedDeployAccountTransaction, ) -> RpcResult { let best_block_hash = self.get_best_block_hash(); + let chain_id = Felt252Wrapper(self.chain_id()?.0); - let transaction: UserTransaction = deploy_account_transaction.try_into().map_err(|e| { - error!("Failed to convert BroadcastedDeployAccountTransaction to UserTransaction, error: {e}",); - StarknetRpcApiError::InternalServerError - })?; + let transaction: AccountTransaction = + try_account_tx_from_broadcasted_deploy_tx(deploy_account_transaction, chain_id).map_err(|e| { + error!("Failed to convert BroadcastedDeployAccountTransaction to AccountTransaction, error: {e}",); + StarknetRpcApiError::InternalServerError + })?; let extrinsic = self.convert_tx_to_extrinsic(best_block_hash, transaction.clone())?; submit_extrinsic(self.pool.clone(), best_block_hash, extrinsic).await?; - let chain_id = Felt252Wrapper(self.chain_id()?.0); - let account_address = match &transaction { - UserTransaction::DeployAccount(tx) => tx.account_address(), + let (contract_address, tx_hash) = match &transaction { + AccountTransaction::DeployAccount(tx) => (tx.contract_address, tx.tx_hash), _ => Err(StarknetRpcApiError::InternalServerError)?, }; Ok(DeployAccountTransactionResult { - transaction_hash: transaction.compute_hash::(chain_id, false).into(), - contract_address: account_address.into(), + transaction_hash: Felt252Wrapper::from(tx_hash).into(), + contract_address: Felt252Wrapper::from(contract_address).into(), }) } } @@ -557,10 +523,12 @@ where /// - `execution_status`: The execution status of the transaction, providing details on the /// execution outcome if the transaction has been processed. fn get_transaction_status(&self, transaction_hash: FieldElement) -> RpcResult { + let transaction_hash: TransactionHash = Felt252Wrapper(transaction_hash).into(); + let substrate_block_hash = self .backend .mapping() - .block_hash_from_transaction_hash(Felt252Wrapper(transaction_hash).into()) + .block_hash_from_transaction_hash(transaction_hash) .map_err(|e| { error!("Failed to get transaction's substrate block hash from mapping_db: {e}"); StarknetRpcApiError::TxnHashNotFound @@ -569,23 +537,6 @@ where let starknet_block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash)?; - let chain_id = self.chain_id()?.0.into(); - - let starknet_tx = - if let Some(tx_hashes) = self.get_cached_transaction_hashes(starknet_block.header().hash::().into()) { - tx_hashes - .into_iter() - .zip(starknet_block.transactions()) - .find(|(tx_hash, _)| *tx_hash == Felt252Wrapper(transaction_hash).into()) - .map(|(_, tx)| to_starknet_core_tx(tx.clone(), transaction_hash)) - } else { - starknet_block - .transactions() - .iter() - .find(|tx| tx.compute_hash::(chain_id, false).0 == transaction_hash) - .map(|tx| to_starknet_core_tx(tx.clone(), transaction_hash)) - }; - let execution_status = { let revert_error = self.get_tx_execution_outcome(substrate_block_hash, transaction_hash)?; @@ -898,15 +849,8 @@ where let starknet_version = starknet_block.header().protocol_version; let block_hash = starknet_block.header().hash::(); - let transaction_hashes = if let Some(tx_hashes) = self.get_cached_transaction_hashes(block_hash.into()) { - let mut v = Vec::with_capacity(tx_hashes.len()); - for tx_hash in tx_hashes { - v.push(Felt252Wrapper::from(tx_hash).into()); - } - v - } else { - starknet_block.transactions_hashes::(chain_id.0.into()).map(FieldElement::from).collect() - }; + let transaction_hashes = + starknet_block.transactions_hashes().map(|txh| Felt252Wrapper::from(txh).into()).collect(); let block_status = match self.backend.messaging().last_synced_l1_block_with_event() { Ok(l1_block) => { if l1_block.block_number >= starknet_block.header().block_number { @@ -1017,9 +961,12 @@ where let best_block_hash = self.get_best_block_hash(); let chain_id = Felt252Wrapper(self.chain_id()?.0); - let transactions = - request.into_iter().map(|tx| tx.try_into()).collect::, _>>().map_err(|e| { - error!("Failed to convert BroadcastedTransaction to UserTransaction: {e}"); + let transactions = request + .into_iter() + .map(|tx| try_account_tx_from_broadcasted_tx(tx, chain_id)) + .collect::, _>>() + .map_err(|e| { + error!("Failed to convert BroadcastedTransaction to AccountTransaction: {e}"); StarknetRpcApiError::InternalServerError })?; @@ -1028,7 +975,12 @@ where let estimates = fee_estimates .into_iter() // FIXME: https://github.com/keep-starknet-strange/madara/issues/329 - .map(|x| FeeEstimate { gas_price: 10, gas_consumed: x.1 as u64, overall_fee: x.0 as u64 }) + .map(|x| FeeEstimate { + gas_price: FieldElement::from(10u128), + gas_consumed: FieldElement::from(x.1), + overall_fee: FieldElement::from(x.0), + unit: PriceUnit::Wei, + }) .collect(); Ok(estimates) @@ -1057,17 +1009,30 @@ where })?; let chain_id = Felt252Wrapper(self.chain_id()?.0); - let message = message.try_into().map_err(|e| { - error!("Failed to convert MsgFromL1 to UserTransaction: {e}"); - StarknetRpcApiError::InternalServerError - })?; + let transaction = { + let calldata = std::iter::once(Felt252Wrapper::from(message.from_address).into()) + .chain(message.payload.into_iter().map(|felt| Felt252Wrapper::from(felt).into())) + .collect(); + let tx = starknet_api::transaction::L1HandlerTransaction { + version: TransactionVersion::ZERO, + nonce: Nonce(StarkFelt::ZERO), + contract_address: Felt252Wrapper::from(message.to_address).into(), + entry_point_selector: Felt252Wrapper::from(message.entry_point_selector).into(), + calldata: Calldata(Arc::new(calldata)), + }; + let tx_hash = tx.compute_hash(chain_id, true); + + // Hardcoded fee fee value as it is not relevant here + L1HandlerTransaction { tx, tx_hash, paid_fee_on_l1: Fee(10) } + }; - let fee_estimate = self.do_estimate_message_fee(substrate_block_hash, message)?; + let fee_estimate = self.do_estimate_message_fee(substrate_block_hash, transaction)?; let estimate = FeeEstimate { gas_price: fee_estimate.0.try_into().map_err(|_| StarknetRpcApiError::InternalServerError)?, - gas_consumed: fee_estimate.2 as u64, - overall_fee: fee_estimate.1 as u64, + gas_consumed: FieldElement::from(fee_estimate.2), + overall_fee: FieldElement::from(fee_estimate.1), + unit: PriceUnit::Wei, }; Ok(estimate) @@ -1106,21 +1071,7 @@ where starknet_block.transactions().get(index as usize).ok_or(StarknetRpcApiError::InvalidTxnIndex)?; let chain_id = self.chain_id()?; - let opt_cached_transaction_hashes = - self.get_cached_transaction_hashes(starknet_block.header().hash::().into()); - - let transaction_hash = if let Some(cached_tx_hashes) = opt_cached_transaction_hashes { - cached_tx_hashes.get(index as usize).map(|&fe| Felt252Wrapper::from(fe).into()).ok_or(CallError::Failed( - anyhow::anyhow!( - "Number of cached tx hashes does not match the number of transactions in block with id {:?}", - block_id - ), - ))? - } else { - transaction.compute_hash::(chain_id.0.into(), false).0 - }; - - Ok(to_starknet_core_tx(transaction.clone(), transaction_hash)) + Ok(to_starknet_core_tx(transaction.clone())) } /// Get block information with full transactions given the block id. @@ -1159,24 +1110,7 @@ where let block_hash = starknet_block.header().hash::(); let starknet_version = starknet_block.header().protocol_version; - - let opt_cached_transaction_hashes = - self.get_cached_transaction_hashes(starknet_block.header().hash::().into()); - let mut transactions = Vec::with_capacity(starknet_block.transactions().len()); - for (index, tx) in starknet_block.transactions().iter().enumerate() { - let tx_hash = if let Some(cached_tx_hashes) = opt_cached_transaction_hashes.as_ref() { - cached_tx_hashes.get(index).map(|&h| Felt252Wrapper::from(h).into()).ok_or(CallError::Failed( - anyhow::anyhow!( - "Number of cached tx hashes does not match the number of transactions in block with hash {:?}", - block_hash - ), - ))? - } else { - tx.compute_hash::(chain_id.0.into(), false).0 - }; - - transactions.push(to_starknet_core_tx(tx.clone(), tx_hash)); - } + let transactions = starknet_block.transactions().iter().map(|tx| to_starknet_core_tx(tx.clone())).collect(); let block_with_txs = BlockWithTxs { // TODO: Get status from block @@ -1386,22 +1320,12 @@ where let starknet_block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash)?; - let chain_id = self.chain_id()?.0.into(); - - let find_tx = - if let Some(tx_hashes) = self.get_cached_transaction_hashes(starknet_block.header().hash::().into()) { - tx_hashes - .into_iter() - .zip(starknet_block.transactions()) - .find(|(tx_hash, _)| *tx_hash == Felt252Wrapper(transaction_hash).into()) - .map(|(_, tx)| to_starknet_core_tx(tx.clone(), transaction_hash)) - } else { - starknet_block - .transactions() - .iter() - .find(|tx| tx.compute_hash::(chain_id, false).0 == transaction_hash) - .map(|tx| to_starknet_core_tx(tx.clone(), transaction_hash)) - }; + let searched_tx_hash: TransactionHash = Felt252Wrapper::from(transaction_hash).into(); + let find_tx = starknet_block + .transactions() + .iter() + .find(|tx| get_transaction_hash(tx) == &searched_tx_hash) + .map(|tx| to_starknet_core_tx(tx.clone())); find_tx.ok_or(StarknetRpcApiError::TxnHashNotFound.into()) } @@ -1433,15 +1357,12 @@ where transaction_hash: FieldElement, ) -> RpcResult { let chain_id = Felt252Wrapper(self.chain_id()?.0); + let transaction_hash = Felt252Wrapper::from(transaction_hash).into(); - let receipt = match self - .backend - .mapping() - .block_hash_from_transaction_hash(Felt252Wrapper::from(transaction_hash).into()) - .map_err(|e| { - error!("Failed to interact with db backend error: {e}"); - StarknetRpcApiError::InternalServerError - })? { + let receipt = match self.backend.mapping().block_hash_from_transaction_hash(transaction_hash).map_err(|e| { + error!("Failed to interact with db backend error: {e}"); + StarknetRpcApiError::InternalServerError + })? { Some(substrate_block_hash) => { self.prepare_tx_receipt(chain_id, transaction_hash, substrate_block_hash).await? } @@ -1478,7 +1399,7 @@ where let transactions = self .get_pending_txs(parent_hash)? .iter() - .map(|tx| tx.compute_hash::(chain_id.0.into(), false).0) + .map(|tx| Felt252Wrapper::from(*get_transaction_hash(tx)).into()) .collect::>(); let pending_block = PendingBlockWithTxHashes { @@ -1500,11 +1421,8 @@ where let latest_block = get_block_by_block_hash(self.client.as_ref(), parent_hash).unwrap_or_default(); let latest_block_header = latest_block.header(); - let transactions = self - .get_pending_txs(parent_hash)? - .iter() - .map(|tx| to_starknet_core_tx(tx.clone(), tx.compute_hash::(chain_id.0.into(), false).0)) - .collect::>(); + let transactions = + self.get_pending_txs(parent_hash)?.iter().map(|tx| to_starknet_core_tx(tx.clone())).collect::>(); let pending_block = PendingBlockWithTxs { transactions, @@ -1517,7 +1435,10 @@ where Ok(pending_block) } - fn get_pending_txs(&self, latest_block: B::Hash) -> Result, StarknetRpcApiError> { + fn get_pending_txs( + &self, + latest_block: B::Hash, + ) -> Result, StarknetRpcApiError> { // Fetch all Pending Txs from Transaction Pool // Operates as RPC Call `author_pendingExtrinsics` // See https://github.com/paritytech/polkadot-sdk/blob/release-polkadot-v1.6.0/substrate/client/rpc/src/author/mod.rs#L153-L155 @@ -1525,14 +1446,15 @@ where let pending_transactions: Vec = self.pool.ready().map(|tx| tx.data().clone()).collect(); // Use Runtime API to filter all Pending Txs - // And get only Starknet Txs (Pallet Starknet calls) as Vec + // And get only Starknet Txs (Pallet Starknet calls) as + // Vec self.filter_extrinsics(latest_block, pending_transactions) } async fn prepare_tx_receipt( &self, chain_id: Felt252Wrapper, - transaction_hash: FieldElement, + transaction_hash: TransactionHash, substrate_block_hash: B::Hash, ) -> Result { let starknet_block: mp_block::Block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash) @@ -1553,15 +1475,7 @@ where let fee_disabled = self.is_transaction_fee_disabled(substrate_block_hash)?; let transactions = self.filter_extrinsics(substrate_block_hash, block_extrinsics)?; - let txn_hashes = self.get_cached_transaction_hashes(starknet_block.header().hash::().into()); - let mut transaction = None; - for (index, tx) in transactions.iter().enumerate() { - let tx_hash = self.try_txn_hash_from_cache(index, &txn_hashes, &transactions, chain_id)?; - if tx_hash == transaction_hash.into() { - transaction = Some(tx); - break; - } - } + let transaction = transactions.iter().find(|tx| get_transaction_hash(tx) == &transaction_hash); if transaction.is_none() { error!( "Failed to find transaction hash in block. Substrate block hash: {substrate_block_hash}, transaction \ @@ -1571,7 +1485,7 @@ where } let transaction = transaction.unwrap(); - let events = self.get_events_for_tx_by_hash(substrate_block_hash, Felt252Wrapper(transaction_hash).into())?; + let events = self.get_events_for_tx_by_hash(substrate_block_hash, transaction_hash)?; let execution_result = { let revert_error = self.get_tx_execution_outcome(substrate_block_hash, transaction_hash)?; @@ -1585,20 +1499,23 @@ where let events_converted: Vec = events.clone().into_iter().map(starknet_api_to_starknet_core_event).collect(); - let actual_fee = if fee_disabled { - FieldElement::ZERO - } else { - // Event { - // from_address: fee_token_address, - // keys: [selector("Transfer")], - // data: [ - // send_from_address, // account_contract_address - // send_to_address, // to (sequencer address) - // expected_fee_value_low, // transfer amount (fee) - // expected_fee_value_high, - // ]}, - // fee transfer must be the last event, except enabled disable-transaction-fee feature - events_converted.last().unwrap().data[2] + let actual_fee = FeePayment { + amount: if fee_disabled { + FieldElement::ZERO + } else { + // Event { + // from_address: fee_token_address, + // keys: [selector("Transfer")], + // data: [ + // send_from_address, // account_contract_address + // send_to_address, // to (sequencer address) + // expected_fee_value_low, // transfer amount (fee) + // expected_fee_value_high, + // ]}, + // fee transfer must be the last event, except enabled disable-transaction-fee feature + events_converted.last().unwrap().data[2] + }, + unit: PriceUnit::Wei, }; let messages = self.get_tx_messages_to_l1(substrate_block_hash, transaction_hash)?; @@ -1619,47 +1536,57 @@ where })?; let simulation = self.simulate_tx(parent_block_hash, transaction.clone(), skip_validate, fee_disabled)?; let execution_resources = actual_resources_to_execution_resources(simulation.actual_resources); + let transaction_hash = Felt252Wrapper::from(transaction_hash).into(); let receipt = match transaction { - mp_transactions::Transaction::Declare(_, _) => TransactionReceipt::Declare(DeclareTransactionReceipt { - transaction_hash, - actual_fee, - finality_status: TransactionFinalityStatus::AcceptedOnL2, - block_hash, - block_number, - messages_sent, - events: events_converted, - execution_result, - execution_resources, - }), - mp_transactions::Transaction::DeployAccount(tx) => { - TransactionReceipt::DeployAccount(DeployAccountTransactionReceipt { - transaction_hash, - actual_fee, - finality_status: TransactionFinalityStatus::AcceptedOnL2, - block_hash, - block_number, - messages_sent, - events: events_converted, - contract_address: tx.get_account_address(), - execution_result, - execution_resources, - }) + blockifier::transaction::transaction_execution::Transaction::AccountTransaction(account_tx) => { + match account_tx { + blockifier::transaction::account_transaction::AccountTransaction::Declare(_) => { + TransactionReceipt::Declare(DeclareTransactionReceipt { + transaction_hash, + actual_fee, + finality_status: TransactionFinalityStatus::AcceptedOnL2, + block_hash, + block_number, + messages_sent, + events: events_converted, + execution_result, + execution_resources, + }) + } + blockifier::transaction::account_transaction::AccountTransaction::DeployAccount(tx) => { + TransactionReceipt::DeployAccount(DeployAccountTransactionReceipt { + transaction_hash, + actual_fee, + finality_status: TransactionFinalityStatus::AcceptedOnL2, + block_hash, + block_number, + messages_sent, + events: events_converted, + contract_address: Felt252Wrapper::from(tx.contract_address).into(), + execution_result, + execution_resources, + }) + } + blockifier::transaction::account_transaction::AccountTransaction::Invoke(_) => { + TransactionReceipt::Invoke(InvokeTransactionReceipt { + transaction_hash, + actual_fee, + finality_status: TransactionFinalityStatus::AcceptedOnL2, + block_hash, + block_number, + messages_sent, + events: events_converted, + execution_result, + execution_resources, + }) + } + } } - mp_transactions::Transaction::Invoke(_) => TransactionReceipt::Invoke(InvokeTransactionReceipt { - transaction_hash, - actual_fee, - finality_status: TransactionFinalityStatus::AcceptedOnL2, - block_hash, - block_number, - messages_sent, - events: events_converted, - execution_result, - execution_resources, - }), - mp_transactions::Transaction::L1Handler(ref tx) => { + blockifier::transaction::transaction_execution::Transaction::L1HandlerTransaction(l1_handler_tx) => { + let message_hash = compute_message_hash(&l1_handler_tx.tx); TransactionReceipt::L1Handler(L1HandlerTransactionReceipt { - message_hash: Hash256::from_felt(&tx.compute_hash::(chain_id, false).0), + message_hash: Hash256::from_bytes(message_hash.to_fixed_bytes()), transaction_hash, actual_fee, finality_status: TransactionFinalityStatus::AcceptedOnL2, @@ -1688,19 +1615,20 @@ where fn get_tx_execution_outcome( &self, substrate_block_hash: B::Hash, - transaction_hash: FieldElement, + transaction_hash: TransactionHash, ) -> Result>, StarknetRpcApiError> { - self.do_get_tx_execution_outcome(substrate_block_hash, Felt252Wrapper(transaction_hash).into()) + self.do_get_tx_execution_outcome(substrate_block_hash, transaction_hash) } fn find_pending_tx( &self, chain_id: Felt252Wrapper, tx_hash: TransactionHash, - ) -> Result, StarknetRpcApiError> { + ) -> Result, StarknetRpcApiError> { let latest_block = self.get_best_block_hash(); - let pending_tx = self.get_pending_txs(latest_block)?.iter().find(|&tx| tx.tx_hash == tx_hash).cloned(); + let pending_tx = + self.get_pending_txs(latest_block)?.iter().find(|&tx| get_transaction_hash(tx) == &tx_hash).cloned(); Ok(pending_tx) } @@ -1708,7 +1636,7 @@ where async fn get_pending_transaction_receipt( &self, chain_id: Felt252Wrapper, - transaction_hash: FieldElement, + transaction_hash: TransactionHash, ) -> Result { let pending_tx = self.find_pending_tx(chain_id, transaction_hash)?.ok_or(StarknetRpcApiError::TxnHashNotFound)?; @@ -1723,49 +1651,56 @@ where let skip_fee_charge = self.is_transaction_fee_disabled(self.get_best_block_hash())?; let simulation = self.simulate_tx(self.get_best_block_hash(), pending_tx.clone(), skip_validate, skip_fee_charge)?; - let actual_fee = simulation.actual_fee.0.into(); + let actual_fee = + FeePayment { amount: Felt252Wrapper::from(simulation.actual_fee.0).into(), unit: PriceUnit::Wei }; let execution_result = revert_error_to_execution_result(simulation.revert_error); let execution_resources = actual_resources_to_execution_resources(simulation.actual_resources); + let transaction_hash = Felt252Wrapper::from(transaction_hash).into(); let receipt = match pending_tx { - mp_transactions::Transaction::Declare(_tx, _contract_class) => { - let receipt = PendingDeclareTransactionReceipt { - transaction_hash, - actual_fee, - messages_sent, - events, - execution_resources, - execution_result, - }; - PendingTransactionReceipt::Declare(receipt) - } - mp_transactions::Transaction::DeployAccount(ref tx) => { - let contract_address = tx.get_account_address(); - let receipt = PendingDeployAccountTransactionReceipt { - transaction_hash, - actual_fee, - messages_sent, - events, - execution_resources, - execution_result, - contract_address, - }; - PendingTransactionReceipt::DeployAccount(receipt) - } - mp_transactions::Transaction::Invoke(_tx) => { - let receipt = PendingInvokeTransactionReceipt { - transaction_hash, - actual_fee, - messages_sent, - events, - execution_resources, - execution_result, - }; - PendingTransactionReceipt::Invoke(receipt) + blockifier::transaction::transaction_execution::Transaction::AccountTransaction(account_tx) => { + match account_tx { + AccountTransaction::Declare(_tx) => { + let receipt = PendingDeclareTransactionReceipt { + transaction_hash, + actual_fee, + messages_sent, + events, + execution_resources, + execution_result, + }; + PendingTransactionReceipt::Declare(receipt) + } + AccountTransaction::DeployAccount(tx) => { + let contract_address = Felt252Wrapper::from(tx.contract_address).into(); + let receipt = PendingDeployAccountTransactionReceipt { + transaction_hash, + actual_fee, + messages_sent, + events, + execution_resources, + execution_result, + contract_address, + }; + PendingTransactionReceipt::DeployAccount(receipt) + } + AccountTransaction::Invoke(_tx) => { + let receipt = PendingInvokeTransactionReceipt { + transaction_hash, + actual_fee, + messages_sent, + events, + execution_resources, + execution_result, + }; + PendingTransactionReceipt::Invoke(receipt) + } + } } - mp_transactions::Transaction::L1Handler(ref tx) => { + blockifier::transaction::transaction_execution::Transaction::L1HandlerTransaction(tx) => { + let message_hash = Hash256::from_bytes(compute_message_hash(&tx.tx).to_fixed_bytes()); let receipt = PendingL1HandlerTransactionReceipt { - message_hash: Hash256::from_felt(&tx.compute_hash::(chain_id, false).0), + message_hash, transaction_hash, actual_fee, messages_sent, @@ -1857,14 +1792,15 @@ fn actual_resources_to_execution_resources(resources: ResourcesMapping) -> Execu // Based on `VM_RESOURCE_FEE_COSTS` // in crates/primitives/fee/src/lib.rs ExecutionResources { - steps: *resources.get("n_steps").unwrap_or(&0), + steps: resources.get("n_steps").cloned().unwrap_or_default(), memory_holes: resources.get("memory_holes").copied(), - range_check_builtin_applications: *resources.get("range_check_builtin").unwrap_or(&0), - pedersen_builtin_applications: *resources.get("pedersen_builtin").unwrap_or(&0), - poseidon_builtin_applications: *resources.get("poseidon_builtin").unwrap_or(&0), - ec_op_builtin_applications: *resources.get("ec_op_builtin").unwrap_or(&0), - ecdsa_builtin_applications: *resources.get("ecdsa_builtin").unwrap_or(&0), - bitwise_builtin_applications: *resources.get("bitwise_builtin").unwrap_or(&0), - keccak_builtin_applications: *resources.get("keccak_builtin").unwrap_or(&0), + range_check_builtin_applications: resources.get("range_check_builtin").cloned(), + pedersen_builtin_applications: resources.get("pedersen_builtin").cloned(), + poseidon_builtin_applications: resources.get("poseidon_builtin").cloned(), + ec_op_builtin_applications: resources.get("ec_op_builtin").cloned(), + ecdsa_builtin_applications: resources.get("ecdsa_builtin").cloned(), + bitwise_builtin_applications: resources.get("bitwise_builtin").cloned(), + keccak_builtin_applications: resources.get("keccak_builtin").cloned(), + segment_arena_builtin: resources.get("segment_arena_builtin").cloned(), } } diff --git a/crates/client/rpc/src/madara_backend_client.rs b/crates/client/rpc/src/madara_backend_client.rs index 909107af5e..3d71d01316 100644 --- a/crates/client/rpc/src/madara_backend_client.rs +++ b/crates/client/rpc/src/madara_backend_client.rs @@ -5,14 +5,14 @@ use sc_client_api::backend::{Backend, StorageProvider}; use sp_api::BlockId; use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; -use starknet_api::hash::StarkHash; +use starknet_api::block::BlockHash; use crate::errors::StarknetRpcApiError; pub fn load_hash( client: &C, backend: &mc_db::Backend, - hash: StarkHash, + hash: BlockHash, ) -> Result, DbError> where B: BlockT, diff --git a/crates/client/rpc/src/runtime_api.rs b/crates/client/rpc/src/runtime_api.rs index eb35f310b9..2c9132a6d5 100644 --- a/crates/client/rpc/src/runtime_api.rs +++ b/crates/client/rpc/src/runtime_api.rs @@ -22,7 +22,6 @@ use sp_runtime::traits::Block as BlockT; use sp_runtime::DispatchError; use starknet_api::core::{ContractAddress, EntryPointSelector}; use starknet_api::transaction::{Calldata, Event, TransactionHash}; -use starknet_core::types::FieldElement; use crate::{Starknet, StarknetRpcApiError}; @@ -160,15 +159,12 @@ where pub fn get_tx_messages_to_l1( &self, substrate_block_hash: B::Hash, - transaction_hash: FieldElement, + transaction_hash: TransactionHash, ) -> RpcApiResult> { - self.client - .runtime_api() - .get_tx_messages_to_l1(substrate_block_hash, Felt252Wrapper(transaction_hash).into()) - .map_err(|e| { - error!("'{e}'"); - StarknetRpcApiError::InternalServerError - }) + self.client.runtime_api().get_tx_messages_to_l1(substrate_block_hash, transaction_hash).map_err(|e| { + error!("'{e}'"); + StarknetRpcApiError::InternalServerError + }) } pub fn is_transaction_fee_disabled(&self, substrate_block_hash: B::Hash) -> RpcApiResult { diff --git a/crates/client/rpc/src/trace_api.rs b/crates/client/rpc/src/trace_api.rs index 07a642a9d0..f2d369299f 100644 --- a/crates/client/rpc/src/trace_api.rs +++ b/crates/client/rpc/src/trace_api.rs @@ -1,5 +1,4 @@ use blockifier::execution::call_info::CallInfo; -use blockifier::execution::contract_class::{ContractClass, ContractClassV1}; use blockifier::state::cached_state::CommitmentStateDiff; use blockifier::transaction::errors::TransactionExecutionError; use blockifier::transaction::objects::TransactionExecutionInfo; @@ -11,8 +10,11 @@ use mc_rpc_core::{StarknetReadRpcApiServer, StarknetTraceRpcApiServer}; use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; use mp_simulations::{SimulationFlags, TransactionSimulationResult}; -use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{DeclareTransaction, Transaction, TxType, UserOrL1HandlerTransaction, UserTransaction}; +use mp_transactions::from_broadcasted_transactions::{ + try_account_tx_from_broadcasted_declare_tx, try_account_tx_from_broadcasted_deploy_tx, + try_account_tx_from_broadcasted_invoke_tx, +}; +use mp_transactions::{get_transaction_hash, TxType}; use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi}; use sc_client_api::{Backend, BlockBackend, StorageProvider}; use sc_transaction_pool::ChainApi; @@ -20,11 +22,10 @@ use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; -use starknet_api::core::ClassHash; use starknet_core::types::{ BlockId, BroadcastedTransaction, DeclareTransactionTrace, DeployAccountTransactionTrace, ExecuteInvocation, - FeeEstimate, InvokeTransactionTrace, L1HandlerTransactionTrace, RevertedInvocation, SimulatedTransaction, - SimulationFlag, StateDiff, TransactionTrace, TransactionTraceWithHash, + FeeEstimate, InvokeTransactionTrace, L1HandlerTransactionTrace, PriceUnit, RevertedInvocation, + SimulatedTransaction, SimulationFlag, StateDiff, TransactionTrace, TransactionTraceWithHash, }; use starknet_ff::FieldElement; use thiserror::Error; @@ -57,27 +58,36 @@ where let chain_id = Felt252Wrapper(self.chain_id()?.0); let best_block_hash = self.get_best_block_hash(); + let mut tx_types = Vec::with_capacity(transactions.len()); + let mut account_transactions = Vec::with_capacity(transactions.len()); + let tx_type_and_tx_iterator = transactions.into_iter().map(|tx| match tx { - BroadcastedTransaction::Invoke(invoke_tx) => invoke_tx.try_into().map(|tx| (TxType::Invoke, tx)), - BroadcastedTransaction::Declare(declare_tx) => declare_tx.try_into().map(|tx| (TxType::Declare, tx)), + BroadcastedTransaction::Invoke(invoke_tx) => { + (TxType::Invoke, try_account_tx_from_broadcasted_invoke_tx(invoke_tx, chain_id)) + } + BroadcastedTransaction::Declare(declare_tx) => { + (TxType::Declare, try_account_tx_from_broadcasted_declare_tx(declare_tx, chain_id)) + } BroadcastedTransaction::DeployAccount(deploy_account_tx) => { - deploy_account_tx.try_into().map(|tx| (TxType::DeployAccount, tx)) + (TxType::DeployAccount, try_account_tx_from_broadcasted_deploy_tx(deploy_account_tx, chain_id)) } }); - let (tx_types, user_transactions) = - itertools::process_results(tx_type_and_tx_iterator, |iter| iter.unzip::<_, _, Vec<_>, Vec<_>>()).map_err( - |e| { - error!("Failed to convert BroadcastedTransaction to UserTransaction: {e}"); - StarknetRpcApiError::InternalServerError - }, - )?; + + for (tx_type, account_tx) in tx_type_and_tx_iterator { + let tx = account_tx.map_err(|e| { + error!("Failed to convert BroadcastedTransaction to AccountTransaction: {e}"); + StarknetRpcApiError::InternalServerError + })?; + account_transactions.push(tx); + tx_types.push(tx_type); + } let simulation_flags = SimulationFlags::from(simulation_flags); let res = self .client .runtime_api() - .simulate_transactions(substrate_block_hash, user_transactions, simulation_flags) + .simulate_transactions(substrate_block_hash, account_transactions, simulation_flags) .map_err(|e| { error!("Request parameters error: {e}"); StarknetRpcApiError::InternalServerError @@ -104,84 +114,7 @@ where StarknetRpcApiError::InternalServerError })?; - let block_transactions = starknet_block - .transactions() - .iter() - .map(|tx| match tx { - Transaction::Invoke(invoke_tx) => { - RpcResult::Ok(UserOrL1HandlerTransaction::User(UserTransaction::Invoke(invoke_tx.clone()))) - } - Transaction::DeployAccount(deploy_account_tx) => { - Ok(UserOrL1HandlerTransaction::User(UserTransaction::DeployAccount(deploy_account_tx.clone()))) - } - Transaction::Declare(declare_tx, _) => { - let class_hash = ClassHash::from(*declare_tx.class_hash()); - - match declare_tx { - DeclareTransaction::V0(_) | DeclareTransaction::V1(_) => { - let contract_class = self - .overrides - .for_block_hash(self.client.as_ref(), substrate_block_hash) - .contract_class_by_class_hash(substrate_block_hash, class_hash) - .ok_or_else(|| { - error!("Failed to retrieve contract class from hash '{class_hash}'"); - StarknetRpcApiError::InternalServerError - })?; - - Ok(UserOrL1HandlerTransaction::User(UserTransaction::Declare( - declare_tx.clone(), - contract_class, - ))) - } - DeclareTransaction::V2(tx) => { - let contract_class = self - .backend - .sierra_classes() - .get_sierra_class(class_hash) - .map_err(|e| { - error!("Failed to fetch sierra class with hash {class_hash}: {e}"); - StarknetRpcApiError::InternalServerError - })? - .ok_or_else(|| { - error!("The sierra class with hash {class_hash} is not present in db backend"); - StarknetRpcApiError::InternalServerError - })?; - let contract_class = mp_transactions::utils::sierra_to_casm_contract_class(contract_class) - .map_err(|e| { - error!("Failed to convert the SierraContractClass to CasmContractClass: {e}"); - StarknetRpcApiError::InternalServerError - })?; - let contract_class = - ContractClass::V1(ContractClassV1::try_from(contract_class).map_err(|e| { - error!( - "Failed to convert the compiler CasmContractClass to blockifier \ - CasmContractClass: {e}" - ); - StarknetRpcApiError::InternalServerError - })?); - - Ok(UserOrL1HandlerTransaction::User(UserTransaction::Declare( - declare_tx.clone(), - contract_class, - ))) - } - } - } - Transaction::L1Handler(handle_l1_message_tx) => { - let chain_id = self.chain_id()?.0.into(); - let tx_hash = handle_l1_message_tx.compute_hash::(chain_id, false); - let paid_fee = - self.backend.l1_handler_paid_fee().get_fee_paid_for_l1_handler_tx(tx_hash.into()).map_err( - |e| { - error!("Failed to retrieve fee paid on l1 for tx with hash `{tx_hash:?}`: {e}"); - StarknetRpcApiError::InternalServerError - }, - )?; - - Ok(UserOrL1HandlerTransaction::L1Handler(handle_l1_message_tx.clone(), paid_fee)) - } - }) - .collect::, _>>()?; + let block_transactions = starknet_block.transactions(); let previous_block_substrate_hash = { let starknet_block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash).map_err(|e| { @@ -232,7 +165,7 @@ where Some(state_diff), ) .map(|trace_root| TransactionTraceWithHash { - transaction_hash: block_transactions[tx_idx].compute_hash::(chain_id, false).into(), + transaction_hash: Felt252Wrapper::from(*get_transaction_hash(&block_transactions[tx_idx])).into(), trace_root, }) }) @@ -351,9 +284,51 @@ fn try_get_function_invocation_from_call_info( calls: inner_calls, events, messages, + execution_resources: vm_to_starknet_rs_exec_resources(&call_info.resources), }) } +fn vm_to_starknet_rs_exec_resources( + resources: &cairo_vm::vm::runners::cairo_runner::ExecutionResources, +) -> starknet_core::types::ExecutionResources { + starknet_core::types::ExecutionResources { + steps: resources.n_steps.try_into().unwrap(), + memory_holes: Some(resources.n_memory_holes.try_into().unwrap()), + range_check_builtin_applications: resources + .builtin_instance_counter + .get("range_check_builtin") + .map(|&v| v.try_into().unwrap()), + pedersen_builtin_applications: resources + .builtin_instance_counter + .get("pedersen_builtin") + .map(|&v| v.try_into().unwrap()), + poseidon_builtin_applications: resources + .builtin_instance_counter + .get("poseidon_builtin") + .map(|&v| v.try_into().unwrap()), + ec_op_builtin_applications: resources + .builtin_instance_counter + .get("ec_op_builtin") + .map(|&v| v.try_into().unwrap()), + ecdsa_builtin_applications: resources + .builtin_instance_counter + .get("ecdsa_builtin") + .map(|&v| v.try_into().unwrap()), + bitwise_builtin_applications: resources + .builtin_instance_counter + .get("bitwise_builtin") + .map(|&v| v.try_into().unwrap()), + keccak_builtin_applications: resources + .builtin_instance_counter + .get("keccak_builtin") + .map(|&v| v.try_into().unwrap()), + segment_arena_builtin: resources + .builtin_instance_counter + .get("segment_arena_builtin") + .map(|&v| v.try_into().unwrap()), + } +} + fn tx_execution_infos_to_tx_trace( tx_type: TxType, tx_exec_info: &TransactionExecutionInfo, @@ -430,7 +405,12 @@ fn tx_execution_infos_to_simulated_transactions( results.push(SimulatedTransaction { transaction_trace, - fee_estimation: FeeEstimate { gas_consumed, gas_price, overall_fee }, + fee_estimation: FeeEstimate { + gas_consumed: FieldElement::from(gas_consumed), + gas_price: FieldElement::from(gas_price), + overall_fee: FieldElement::from(overall_fee), + unit: PriceUnit::Wei, + }, }); } Err(_) => { diff --git a/crates/pallets/starknet/runtime_api/src/lib.rs b/crates/pallets/starknet/runtime_api/src/lib.rs index 16970e3a45..ebfb6787b6 100644 --- a/crates/pallets/starknet/runtime_api/src/lib.rs +++ b/crates/pallets/starknet/runtime_api/src/lib.rs @@ -73,7 +73,7 @@ sp_api::decl_runtime_apis! { /// Re-execute a block and return the TransactionExecutionInfos of every transaction in it, in the same order fn re_execute_transactions(transactions: Vec) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError>; - fn get_index_and_tx_for_tx_hash(xts: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: TransactionHash) -> Option<(u32, Transaction)>; + fn get_index_and_tx_for_tx_hash(xts: Vec<::Extrinsic>, tx_hash: TransactionHash) -> Option<(u32, Transaction)>; fn get_events_for_tx_by_hash(tx_hash: TransactionHash) -> Vec; /// Return the outcome of the tx execution diff --git a/crates/pallets/starknet/src/blockifier_state_adapter.rs b/crates/pallets/starknet/src/blockifier_state_adapter.rs index e966cd5f0b..370bf0985e 100644 --- a/crates/pallets/starknet/src/blockifier_state_adapter.rs +++ b/crates/pallets/starknet/src/blockifier_state_adapter.rs @@ -69,15 +69,15 @@ impl StateReader for BlockifierStateAdapter { } fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { - Ok(Pallet::::contract_class_hash_by_address(contract_address)) + Ok(ClassHash(Pallet::::contract_class_hash_by_address(contract_address))) } fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { - Pallet::::contract_class_by_class_hash(class_hash).ok_or(StateError::UndeclaredClassHash(class_hash)) + Pallet::::contract_class_by_class_hash(class_hash.0).ok_or(StateError::UndeclaredClassHash(class_hash)) } fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { - Pallet::::compiled_class_hash_by_class_hash(class_hash).ok_or(StateError::UndeclaredClassHash(class_hash)) + Pallet::::compiled_class_hash_by_class_hash(class_hash.0).ok_or(StateError::UndeclaredClassHash(class_hash)) } } @@ -110,13 +110,13 @@ impl State for BlockifierStateAdapter { fn set_class_hash_at(&mut self, contract_address: ContractAddress, class_hash: ClassHash) -> StateResult<()> { self.class_hash_update += 1; - crate::ContractClassHashes::::insert(contract_address, class_hash); + crate::ContractClassHashes::::insert(contract_address, class_hash.0); Ok(()) } fn set_contract_class(&mut self, class_hash: ClassHash, contract_class: ContractClass) -> StateResult<()> { - crate::ContractClasses::::insert(class_hash, contract_class); + crate::ContractClasses::::insert(class_hash.0, contract_class); Ok(()) } @@ -127,7 +127,7 @@ impl State for BlockifierStateAdapter { compiled_class_hash: CompiledClassHash, ) -> StateResult<()> { self.compiled_class_hash_update += 1; - crate::CompiledClassHashes::::insert(class_hash, compiled_class_hash); + crate::CompiledClassHashes::::insert(class_hash.0, compiled_class_hash); Ok(()) } diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs index 5a7c1f9859..b5d4b680d3 100644 --- a/crates/pallets/starknet/src/lib.rs +++ b/crates/pallets/starknet/src/lib.rs @@ -90,7 +90,7 @@ use mp_storage::{StarknetStorageSchemaVersion, PALLET_STARKNET_SCHEMA}; use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::DigestItem; use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::{ChainId, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::core::{ChainId, ClassHash, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::deprecated_contract_class::EntryPointType; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::StorageKey; @@ -121,6 +121,7 @@ macro_rules! log { #[frame_support::pallet] pub mod pallet { use blockifier::transaction::account_transaction::AccountTransaction; + use starknet_api::core::ClassHash; use super::*; @@ -332,14 +333,14 @@ pub mod pallet { /// second element is the contract class hash. /// This can be used to start the chain with a set of pre-deployed contracts, for example in /// a test environment or in the case of a migration of an existing chain state. - pub contracts: Vec<(ContractAddress, SierraClassHash)>, - pub sierra_to_casm_class_hash: Vec<(SierraClassHash, CasmClassHash)>, + pub contracts: Vec<(ContractAddress, ClassHash)>, + pub sierra_to_casm_class_hash: Vec<(ClassHash, CompiledClassHash)>, /// The contract classes to be deployed at genesis. /// This is a vector of tuples, where the first element is the contract class hash and the /// second element is the contract class definition. /// Same as `contracts`, this can be used to start the chain with a set of pre-deployed /// contracts classes. - pub contract_classes: Vec<(SierraClassHash, ContractClass)>, + pub contract_classes: Vec<(ClassHash, ContractClass)>, pub storage: Vec<(ContractStorageKey, StarkFelt)>, /// The address of the fee token. /// Must be set to the address of the fee token ERC20 contract. @@ -373,26 +374,26 @@ pub mod pallet { ); for (class_hash, contract_class) in self.contract_classes.iter() { - ContractClasses::::insert(class_hash, contract_class); + ContractClasses::::insert(class_hash.0, contract_class); } for (sierra_class_hash, casm_class_hash) in self.sierra_to_casm_class_hash.iter() { assert!( - ContractClasses::::contains_key(sierra_class_hash), + ContractClasses::::contains_key(sierra_class_hash.0), "Sierra class hash {} does not exist in contract_classes", sierra_class_hash, ); - CompiledClassHashes::::insert(sierra_class_hash, CompiledClassHash(casm_class_hash.0)); + CompiledClassHashes::::insert(sierra_class_hash.0, casm_class_hash); } for (address, class_hash) in self.contracts.iter() { assert!( - ContractClasses::::contains_key(class_hash), + ContractClasses::::contains_key(class_hash.0), "Class hash {} does not exist in contract_classes", class_hash, ); - ContractClassHashes::::insert(address, class_hash); + ContractClassHashes::::insert(address, class_hash.0); } for (key, value) in self.storage.iter() { @@ -540,7 +541,7 @@ pub mod pallet { // Check class hash is not already declared ensure!( - !ContractClasses::::contains_key(transaction.tx().class_hash()), + !ContractClasses::::contains_key(transaction.tx().class_hash().0), Error::::ClassHashAlreadyDeclared ); // Check if contract is deployed @@ -883,7 +884,7 @@ impl Pallet { let class_hash = ContractClassHashes::::try_get(address).map_err(|_| Error::::ContractNotFound)?; let entrypoint = CallEntryPoint { - class_hash: Some(class_hash), + class_hash: Some(ClassHash(class_hash)), code_address: None, entry_point_type: EntryPointType::External, entry_point_selector: function_selector, diff --git a/crates/pallets/starknet/src/tests/account_helper.rs b/crates/pallets/starknet/src/tests/account_helper.rs index 2e032c1054..3d21be0694 100644 --- a/crates/pallets/starknet/src/tests/account_helper.rs +++ b/crates/pallets/starknet/src/tests/account_helper.rs @@ -1,17 +1,18 @@ -use mp_felt::Felt252Wrapper; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::ContractAddressSalt; use super::mock::AccountType; use crate::tests::mock::{get_account_address, AccountTypeV0Inner}; #[test] fn given_salt_should_calculate_new_contract_addr() { - let salt = Felt252Wrapper::from_hex_be("0x000000000000000000000000000000000000000000000000000000000000BEEF") - .unwrap() - .into(); - let addr_0 = get_account_address(salt, AccountType::V0(AccountTypeV0Inner::Argent)); - let salt = Felt252Wrapper::from_hex_be("0x000000000000000000000000000000000000000000000000000000000000DEAD") - .unwrap() - .into(); - let addr_1 = get_account_address(salt, AccountType::V0(AccountTypeV0Inner::Argent)); + let salt = ContractAddressSalt( + StarkFelt::try_from("0x000000000000000000000000000000000000000000000000000000000000BEEF").unwrap(), + ); + let addr_0 = get_account_address(Some(salt), AccountType::V0(AccountTypeV0Inner::Argent)); + let salt = ContractAddressSalt( + StarkFelt::try_from("0x000000000000000000000000000000000000000000000000000000000000DEAD").unwrap(), + ); + let addr_1 = get_account_address(Some(salt), AccountType::V0(AccountTypeV0Inner::Argent)); assert_ne!(addr_0, addr_1); } diff --git a/crates/pallets/starknet/src/tests/block.rs b/crates/pallets/starknet/src/tests/block.rs index 571a61407b..5b2bdfad1a 100644 --- a/crates/pallets/starknet/src/tests/block.rs +++ b/crates/pallets/starknet/src/tests/block.rs @@ -5,10 +5,9 @@ use blockifier::blockifier::block::GasPrices; use blockifier::transaction::objects::FeeType; use frame_support::assert_ok; use mp_digest_log::{ensure_log, find_starknet_block}; -use mp_felt::Felt252Wrapper; use mp_sequencer_address::DEFAULT_SEQUENCER_ADDRESS; use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; +use starknet_api::core::{ChainId, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use super::mock::default_mock::*; @@ -58,12 +57,12 @@ fn store_block_with_pending_transactions_works() { // perform transactions // first invoke transaction - let transaction = get_invoke_dummy(Felt252Wrapper::ZERO); + let transaction = get_invoke_dummy(Nonce(StarkFelt::ZERO)); assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction.into())); // second invoke transaction - let transaction = get_invoke_dummy(Felt252Wrapper::ONE); + let transaction = get_invoke_dummy(Nonce(StarkFelt::ONE)); assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction.into())); diff --git a/crates/pallets/starknet/src/tests/build_genesis_config.rs b/crates/pallets/starknet/src/tests/build_genesis_config.rs index b85ec29c42..b1f66218e3 100644 --- a/crates/pallets/starknet/src/tests/build_genesis_config.rs +++ b/crates/pallets/starknet/src/tests/build_genesis_config.rs @@ -1,5 +1,5 @@ use sp_runtime::BuildStorage; -use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress}; use super::mock::default_mock; use super::utils::get_contract_class; @@ -9,7 +9,7 @@ use crate::GenesisConfig; fn works_when_sierra_clash_hash_in_mapping_is_known() { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let genesis: GenesisConfig = GenesisConfig { - sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), ClassHash(42u8.into()))], + sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), CompiledClassHash(42u8.into()))], contract_classes: vec![(ClassHash(1u8.into()), get_contract_class("ERC20.json", 0))], ..Default::default() }; @@ -21,7 +21,7 @@ fn works_when_sierra_clash_hash_in_mapping_is_known() { fn fails_when_only_casm_clash_hash_in_mapping_is_known() { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let genesis: GenesisConfig = GenesisConfig { - sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), ClassHash(42u8.into()))], + sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), CompiledClassHash(42u8.into()))], contract_classes: vec![(ClassHash(42u8.into()), get_contract_class("ERC20.json", 0))], ..Default::default() }; @@ -33,7 +33,7 @@ fn fails_when_only_casm_clash_hash_in_mapping_is_known() { fn fail_with_unknown_class_hash_in_sierra_mappings() { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let genesis: GenesisConfig = GenesisConfig { - sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), ClassHash(42u8.into()))], + sierra_to_casm_class_hash: vec![(ClassHash(1u8.into()), CompiledClassHash(42u8.into()))], ..Default::default() }; genesis.assimilate_storage(&mut t).unwrap(); diff --git a/crates/pallets/starknet/src/tests/call_contract.rs b/crates/pallets/starknet/src/tests/call_contract.rs index 06ca66d1c7..962dd26989 100644 --- a/crates/pallets/starknet/src/tests/call_contract.rs +++ b/crates/pallets/starknet/src/tests/call_contract.rs @@ -1,9 +1,10 @@ +use std::sync::Arc; + use frame_support::assert_ok; use mp_felt::Felt252Wrapper; -use mp_transactions::InvokeTransactionV1; -use starknet_api::core::{ContractAddress, EntryPointSelector, PatriciaKey}; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::Calldata; +use starknet_api::transaction::{Calldata, Fee, InvokeTransactionV1, TransactionSignature}; use super::constants::TOKEN_CONTRACT_CLASS_HASH; use super::mock::default_mock::*; @@ -20,28 +21,27 @@ fn given_call_contract_call_works() { // Deploy ERC20 Contract, as it is already declared in fixtures // Deploy ERC20 contract - let constructor_calldata: Vec = vec![ - sender_account.into(), // Simple contract address - Felt252Wrapper::from_hex_be("0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8").unwrap(), // deploy_contract selector - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000009").unwrap(), // Calldata len - Felt252Wrapper::from_hex_be(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash - Felt252Wrapper::ONE, // Contract address salt - Felt252Wrapper::from_hex_be("0x6").unwrap(), // Constructor_calldata_len - Felt252Wrapper::from_hex_be("0xA").unwrap(), // Name - Felt252Wrapper::from_hex_be("0x1").unwrap(), // Symbol - Felt252Wrapper::from_hex_be("0x2").unwrap(), // Decimals - Felt252Wrapper::from_hex_be("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply low - Felt252Wrapper::from_hex_be("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply high - sender_account.into(), // recipient - ]; + let constructor_calldata = Calldata(Arc::new(vec![ + sender_account.0.0, // Simple contract address + StarkFelt::try_from("0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8").unwrap(), // deploy_contract selector + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000009").unwrap(), // Calldata len + StarkFelt::try_from(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash + StarkFelt::ONE, // Contract address salt + StarkFelt::try_from("0x6").unwrap(), // Constructor_calldata_len + StarkFelt::try_from("0xA").unwrap(), // Name + StarkFelt::try_from("0x1").unwrap(), // Symbol + StarkFelt::try_from("0x2").unwrap(), // Decimals + StarkFelt::try_from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply low + StarkFelt::try_from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply high + sender_account.0.0, // recipient + ])); let deploy_transaction = InvokeTransactionV1 { - sender_address: sender_account.into(), - signature: vec![], - nonce: Felt252Wrapper::ZERO, + sender_address: sender_account, + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), calldata: constructor_calldata, - max_fee: u128::MAX, - offset_version: false, + max_fee: Fee(u128::MAX), }; assert_ok!(Starknet::invoke(origin, deploy_transaction.into())); diff --git a/crates/pallets/starknet/src/tests/constants.rs b/crates/pallets/starknet/src/tests/constants.rs index 38c54e982e..989deda409 100644 --- a/crates/pallets/starknet/src/tests/constants.rs +++ b/crates/pallets/starknet/src/tests/constants.rs @@ -1,5 +1,4 @@ use lazy_static::lazy_static; -use mp_felt::Felt252Wrapper; use starknet_api::hash::StarkFelt; use starknet_api::transaction::ContractAddressSalt; @@ -28,8 +27,9 @@ pub const MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS: &str = // salts for address calculation lazy_static! { - pub static ref SALT: Felt252Wrapper = - Felt252Wrapper::from_hex_be("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap(); + pub static ref SALT: ContractAddressSalt = ContractAddressSalt( + StarkFelt::try_from("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap() + ); pub static ref TEST_ACCOUNT_SALT: ContractAddressSalt = ContractAddressSalt( StarkFelt::try_from("0x0780f72e33c1508df24d8f00a96ecc6e08a850ecb09f7e6dff6a81624c0ef46a").unwrap() ); diff --git a/crates/pallets/starknet/src/tests/declare_tx.rs b/crates/pallets/starknet/src/tests/declare_tx.rs index d88130813b..3eb6671582 100644 --- a/crates/pallets/starknet/src/tests/declare_tx.rs +++ b/crates/pallets/starknet/src/tests/declare_tx.rs @@ -1,5 +1,6 @@ use assert_matches::assert_matches; -use blockifier::transaction::transactions::DeclareTransaction; +use blockifier::execution::contract_class::ClassInfo; +use blockifier::transaction::transactions::DeclareTransaction as BlockifierDeclareTransaction; use frame_support::{assert_err, assert_ok}; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; @@ -7,48 +8,70 @@ use sp_runtime::traits::ValidateUnsigned; use sp_runtime::transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, }; -use starknet_api::core::{ClassHash, Nonce}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{DeclareTransaction as StarknetApiDeclareTransaction, DeclareTransactionV0V1}; -use blockifier::transaction::transactions::DeclareTransaction as BlockifierDeclareTransaction; +use starknet_api::transaction::{ + DeclareTransaction as StarknetApiDeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, Fee, + TransactionSignature, +}; use starknet_crypto::FieldElement; use super::mock::default_mock::*; use super::mock::*; use super::utils::{get_contract_class, sign_message_hash}; -use crate::tests::{get_declare_dummy, set_nonce}; -use crate::{Config, Error}; +use crate::tests::set_nonce; +use crate::Error; + +fn create_declare_erc20_v0_transaction( + chain_id: Felt252Wrapper, + account_type: AccountType, + sender_address: Option, + signature: Option, +) -> BlockifierDeclareTransaction { + let sender_address = sender_address.unwrap_or_else(|| get_account_address(None, account_type)); + + let erc20_class = get_contract_class("ERC20.json", 0); + let erc20_class_hash = + ClassHash(StarkFelt::try_from("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap()); + + let tx = StarknetApiDeclareTransaction::V0(DeclareTransactionV0V1 { + max_fee: Fee(u128::MAX), + signature: Default::default(), + nonce: Nonce(StarkFelt::ZERO), + class_hash: erc20_class_hash, + sender_address, + }); -fn create_declare_tx(declare_transaction: DeclareTransaction) -> + let tx_hash = tx.compute_hash(chain_id, false); + // Force to do that because ComputeTransactionHash cannot be implemented on DeclareTransactionV0V1 + // directly... + if let StarknetApiDeclareTransaction::V0(tx) = tx { + tx.signature = signature.unwrap_or_else(|| sign_message_hash(tx_hash)); + } + + BlockifierDeclareTransaction { + tx, + tx_hash, + only_query: false, + class_info: ClassInfo::new(&erc20_class, 0, 1).unwrap(), + } +} #[test] fn given_contract_declare_tx_works_once_not_twice() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - let account_addr = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); + let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); - let transaction = DeclareTransaction::new(DeclareTransaction::V1(DeclareTransactionV0V1 { max_fee: todo!(), signature: todo!(), nonce: todo!(), class_hash: todo!(), sender_address: todo!() }), , ); - let transaction = DeclareTransactionV1 { - sender_address: account_addr.into(), - class_hash: erc20_class_hash, - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, - }; + let transaction = + create_declare_erc20_v0_transaction(chain_id, AccountType::V0(AccountTypeV0Inner::NoValidate), None, None); - assert_ok!(Starknet::declare(none_origin.clone(), transaction.clone().into(), erc20_class.clone())); + assert_ok!(Starknet::declare(none_origin.clone(), transaction.clone().into())); // TODO: Uncomment once we have ABI support // assert_eq!(Starknet::contract_class_by_class_hash(erc20_class_hash), erc20_class); - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::ClassHashAlreadyDeclared - ); + assert_err!(Starknet::declare(none_origin, transaction.into()), Error::::ClassHashAlreadyDeclared); }); } @@ -58,204 +81,75 @@ fn given_contract_declare_tx_fails_sender_not_deployed() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - - // Wrong address (not deployed) - let contract_address = - Felt252Wrapper::from_hex_be("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd31f").unwrap(); - - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); - - let transaction = DeclareTransactionV1 { - sender_address: contract_address, - class_hash: erc20_class_hash, - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, - }; - - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::AccountNotDeployed - ); - }) -} - -#[test] -fn given_contract_declare_on_openzeppelin_account_then_it_works() { - new_test_ext::().execute_with(|| { - basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::ZERO, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = *transaction.class_hash(); - assert_ok!(Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone(), contract_class: erc20_class.clone() }, + // Wrong address (not deployed) + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd31f").unwrap(), )); - assert_ok!(Starknet::declare(none_origin, transaction, erc20_class.clone())); - assert_eq!(Starknet::contract_class_by_class_hash(ClassHash::from(erc20_class_hash)).unwrap(), erc20_class); - }); -} - -#[test] -fn given_contract_declare_on_openzeppelin_account_with_incorrect_signature_then_it_fails() { - new_test_ext::().execute_with(|| { - basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - - let account_addr = get_account_address(None, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); - - let transaction = DeclareTransactionV1 { - max_fee: u128::MAX, - signature: vec![Felt252Wrapper::ZERO, Felt252Wrapper::ONE], - nonce: Felt252Wrapper::ZERO, - class_hash: erc20_class_hash, - sender_address: account_addr.into(), - offset_version: false, - }; - - assert_matches!( - Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone().into(), contract_class: erc20_class.clone() }, - ), - Err(TransactionValidityError::Invalid(_)) - ); - - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); - }); -} - -#[test] -fn given_contract_declare_on_braavos_account_then_it_works() { - new_test_ext::().execute_with(|| { - basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::ZERO, AccountType::V0(AccountTypeV0Inner::Braavos)); - let erc20_class_hash = *transaction.class_hash(); - let erc20_class = get_contract_class("ERC20.json", 0); - - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone(), contract_class: erc20_class.clone() }, + let transaction = create_declare_erc20_v0_transaction( + chain_id, + AccountType::V0(AccountTypeV0Inner::NoValidate), + Some(contract_address), + None, ); - assert_ok!(validate_result); - - assert_ok!(Starknet::declare(none_origin, transaction, erc20_class.clone())); - assert_eq!(Starknet::contract_class_by_class_hash(ClassHash::from(erc20_class_hash)).unwrap(), erc20_class); - }); + assert_err!(Starknet::declare(none_origin, transaction), Error::::AccountNotDeployed); + }) } #[test] -fn given_contract_declare_on_braavos_account_with_incorrect_signature_then_it_fails() { +fn given_contract_declare_on_all_account_types_then_it_works() { new_test_ext::().execute_with(|| { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let account_addr = get_account_address(None, AccountType::V0(AccountTypeV0Inner::Braavos)); - - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); - - let transaction = DeclareTransactionV1 { - max_fee: u128::MAX, - signature: vec![Felt252Wrapper::ZERO, Felt252Wrapper::ONE], - nonce: Felt252Wrapper::ZERO, - class_hash: erc20_class_hash, - sender_address: account_addr.into(), - offset_version: false, - }; - - assert_matches!( - Starknet::validate_unsigned( + for account_type in [AccountTypeV0Inner::Openzeppelin, AccountTypeV0Inner::Argent, AccountTypeV0Inner::Braavos] + { + let transaction = + create_declare_erc20_v0_transaction(Starknet::chain_id(), AccountType::V0(account_type), None, None); + assert_ok!(Starknet::validate_unsigned( TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone().into(), contract_class: erc20_class.clone() }, - ), - Err(TransactionValidityError::Invalid(_)) - ); - - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); + &crate::Call::declare { transaction: transaction.clone() }, + )); + + assert_ok!(Starknet::declare(none_origin, transaction)); + assert_eq!( + Starknet::contract_class_by_class_hash(transaction.tx.class_hash().0).unwrap(), + transaction.class_info.contract_class() + ); + } }); } #[test] -fn given_contract_declare_on_argent_account_then_it_works() { +fn given_contract_declare_on_all_account_types_with_incorrect_signature_then_it_fails() { new_test_ext::().execute_with(|| { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::ZERO, AccountType::V0(AccountTypeV0Inner::Argent)); - let erc20_class_hash = *transaction.class_hash(); - let erc20_class = get_contract_class("ERC20.json", 0); - - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone(), contract_class: erc20_class.clone() }, - ); - assert_ok!(validate_result); - - assert_ok!(Starknet::declare(none_origin, transaction, erc20_class.clone())); - assert_eq!(Starknet::contract_class_by_class_hash(ClassHash::from(erc20_class_hash)).unwrap(), erc20_class); - }); -} - -#[test] -fn given_contract_declare_on_argent_account_with_incorrect_signature_then_it_fails() { - new_test_ext::().execute_with(|| { - basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - - let account_addr = get_account_address(None, AccountType::V0(AccountTypeV0Inner::Argent)); - - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); - - let transaction = DeclareTransactionV1 { - max_fee: u128::MAX, - signature: vec![Felt252Wrapper::ZERO, Felt252Wrapper::ONE], - nonce: Felt252Wrapper::ZERO, - class_hash: erc20_class_hash, - sender_address: account_addr.into(), - offset_version: false, - }; - - assert_matches!( - Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone().into(), contract_class: erc20_class.clone() }, - ), - Err(TransactionValidityError::Invalid(_)) - ); - - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); + for account_type in [AccountTypeV0Inner::Openzeppelin, AccountTypeV0Inner::Argent, AccountTypeV0Inner::Braavos] + { + let transaction = create_declare_erc20_v0_transaction( + Starknet::chain_id(), + AccountType::V0(account_type), + None, + Some(TransactionSignature(vec![StarkFelt::ZERO, StarkFelt::ONE])), + ); + + assert_matches!( + Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::declare { transaction: transaction.clone() }, + ), + Err(TransactionValidityError::Invalid(_)) + ); + + assert_err!( + Starknet::declare(none_origin, transaction.into()), + Error::::TransactionExecutionFailed + ); + } }); } @@ -268,38 +162,38 @@ fn given_contract_declare_on_cairo_1_no_validate_account_then_it_works() { let account_addr = get_account_address(None, AccountType::V1(AccountTypeV1Inner::NoValidate)); let hello_starknet_class = get_contract_class("HelloStarknet.casm.json", 1); - let hello_starknet_class_hash = - Felt252Wrapper::from_hex_be("0x05518b17fb5c84683ba37eba8a682b7a6f330911c2216c52c6badff69cc2ec13").unwrap(); - let hello_starknet_compiled_class_hash = - Felt252Wrapper::from_hex_be("0x00df4d3042eec107abe704619f13d92bbe01a58029311b7a1886b23dcbb4ea87").unwrap(); + let hello_starknet_class_hash = ClassHash( + StarkFelt::try_from("0x05518b17fb5c84683ba37eba8a682b7a6f330911c2216c52c6badff69cc2ec13").unwrap(), + ); + let hello_starknet_compiled_class_hash = CompiledClassHash( + StarkFelt::try_from("0x00df4d3042eec107abe704619f13d92bbe01a58029311b7a1886b23dcbb4ea87").unwrap(), + ); - let mut transaction = DeclareTransactionV2 { + let mut tx = DeclareTransactionV2 { sender_address: account_addr.into(), class_hash: hello_starknet_class_hash, compiled_class_hash: hello_starknet_compiled_class_hash, - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), + }; + let tx_hash = tx.compute_hash(Starknet::chain_id(), false); + tx.signature = sign_message_hash(tx_hash); + + let transaction = BlockifierDeclareTransaction { + tx: StarknetApiDeclareTransaction::V2(tx), + tx_hash, + only_query: false, + class_info: ClassInfo::new(&hello_starknet_class, 1, 1).unwrap(), }; - - let chain_id = Starknet::chain_id(); - let transaction_hash = transaction.compute_hash::<::SystemHash>(chain_id, false); - transaction.signature = sign_message_hash(transaction_hash); assert_ok!(Starknet::validate_unsigned( TransactionSource::InBlock, - &crate::Call::declare { - transaction: transaction.clone().into(), - contract_class: hello_starknet_class.clone() - }, + &crate::Call::declare { transaction: transaction.clone() }, )); - assert_ok!(Starknet::declare(none_origin, transaction.into(), hello_starknet_class.clone())); - assert_eq!( - Starknet::contract_class_by_class_hash(ClassHash::from(hello_starknet_class_hash)).unwrap(), - hello_starknet_class - ); + assert_ok!(Starknet::declare(none_origin, transaction.into())); + assert_eq!(Starknet::contract_class_by_class_hash(hello_starknet_class_hash.0).unwrap(), hello_starknet_class); }); } @@ -307,16 +201,15 @@ fn given_contract_declare_on_cairo_1_no_validate_account_then_it_works() { fn test_verify_tx_longevity() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::ZERO, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let erc20_class = get_contract_class("ERC20.json", 0); + let transaction = create_declare_erc20_v0_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + ); - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction, contract_class: erc20_class }, - ) - .unwrap(); + let validate_result = + Starknet::validate_unsigned(TransactionSource::InBlock, &crate::Call::declare { transaction }).unwrap(); assert_eq!(validate_result.longevity, TransactionLongevity::get()); }); @@ -327,23 +220,30 @@ fn test_verify_require_tag() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::ONE, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let erc20_class = get_contract_class("ERC20.json", 0); + let transaction = create_declare_erc20_v0_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + ); let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone(), contract_class: erc20_class }, + &crate::Call::declare { transaction: transaction.clone() }, ) .unwrap(); let valid_transaction_expected = ValidTransaction::with_tag_prefix("starknet") .priority(u64::MAX) - .and_provides((*transaction.sender_address(), *transaction.nonce())) + .and_provides((*transaction.tx.sender_address(), *transaction.tx.nonce())) .longevity(TransactionLongevity::get()) .propagate(true) - .and_requires((*transaction.sender_address(), Felt252Wrapper(transaction.nonce().0 - FieldElement::ONE))) + .and_requires(( + *transaction.tx.sender_address(), + Felt252Wrapper::from( + FieldElement::from(Felt252Wrapper::from(transaction.tx.nonce())) - FieldElement::ONE, + ), + )) .build() .unwrap(); @@ -356,16 +256,16 @@ fn test_verify_nonce_in_unsigned_tx() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = get_declare_dummy( + let transaction = create_declare_erc20_v0_transaction( Starknet::chain_id(), - Felt252Wrapper::ONE, AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, ); - let erc20_class = get_contract_class("ERC20.json", 0); - let tx_sender = (*transaction.sender_address()).into(); + let tx_sender = transaction.tx.sender_address(); let tx_source = TransactionSource::InBlock; - let call = crate::Call::declare { transaction, contract_class: erc20_class }; + let call = crate::Call::declare { transaction }; assert!(Starknet::validate_unsigned(tx_source, &call).is_ok()); diff --git a/crates/pallets/starknet/src/tests/deploy_account_tx.rs b/crates/pallets/starknet/src/tests/deploy_account_tx.rs index afa0cc8718..b785dda454 100644 --- a/crates/pallets/starknet/src/tests/deploy_account_tx.rs +++ b/crates/pallets/starknet/src/tests/deploy_account_tx.rs @@ -1,12 +1,15 @@ +use blockifier::transaction::transactions::DeployAccountTransaction; use frame_support::{assert_err, assert_ok}; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::DeployAccountTransaction; use sp_runtime::traits::ValidateUnsigned; use sp_runtime::transaction_validity::{InvalidTransaction, TransactionSource, TransactionValidityError}; -use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{Event as StarknetEvent, EventContent, EventData, EventKey, TransactionHash}; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, DeployAccountTransactionV1, Event as StarknetEvent, EventContent, EventData, + EventKey, Fee, TransactionHash, TransactionSignature, +}; use starknet_core::utils::get_selector_from_name; use starknet_crypto::FieldElement; @@ -15,37 +18,64 @@ use super::mock::*; use super::utils::{sign_message_hash, sign_message_hash_braavos}; use crate::tests::constants::{ACCOUNT_PUBLIC_KEY, SALT, TRANSFER_SELECTOR_NAME}; use crate::tests::{get_deploy_account_dummy, set_infinite_tokens, set_nonce}; -use crate::{Config, Error, StorageView}; +use crate::{Error, StorageView}; + +fn deploy_v1_to_blockifier_deploy( + tx: DeployAccountTransactionV1, + chain_id: Felt252Wrapper, +) -> DeployAccountTransaction { + let tx_hash = tx.compute_hash(chain_id, false); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + + DeployAccountTransaction::new( + starknet_api::transaction::DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) +} + +fn helper_create_deploy_account_tx( + chain_id: Felt252Wrapper, + salt: ContractAddressSalt, + calldata: Calldata, + account_class_hash: ClassHash, +) -> DeployAccountTransaction { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: salt, + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + + deploy_v1_to_blockifier_deploy(tx, chain_id) +} #[test] fn given_contract_run_deploy_account_tx_works() { new_test_ext::().execute_with(|| { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); // TEST ACCOUNT CONTRACT // - ref testnet tx(0x0751b4b5b95652ad71b1721845882c3852af17e2ed0c8d93554b5b292abb9810) - let salt = - Felt252Wrapper::from_hex_be("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap(); + let salt = ContractAddressSalt( + StarkFelt::try_from("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap(), + ); let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::NoValidate)); - let deploy_tx = DeployAccountTransaction { - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - contract_address_salt: salt, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, - }; - - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); - - let chain_id = Starknet::chain_id(); - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(chain_id, false); + let deploy_tx = helper_create_deploy_account_tx(chain_id, salt, calldata, account_class_hash); + set_infinite_tokens::(&deploy_tx.contract_address); assert_ok!(Starknet::deploy_account(none_origin, deploy_tx)); - assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), account_class_hash.0); let expected_fee_transfer_event = StarknetEvent { content: EventContent { @@ -53,7 +83,7 @@ fn given_contract_run_deploy_account_tx_works() { Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap()).into(), )], data: EventData(vec![ - address.0.0, // From + deploy_tx.contract_address.0.0, // From StarkFelt::try_from("0xdead").unwrap(), // To StarkFelt::try_from("0x18a6").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high @@ -62,7 +92,7 @@ fn given_contract_run_deploy_account_tx_works() { from_address: Starknet::fee_token_addresses().eth_fee_token_address, }; - let events = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events = Starknet::tx_events(TransactionHash::from(deploy_tx.tx_hash)); assert_eq!(expected_fee_transfer_event, events.last().unwrap().clone()); }); } @@ -72,23 +102,13 @@ fn given_contract_run_deploy_account_tx_twice_fails() { new_test_ext::().execute_with(|| { basic_test_setup(2); + let chain_id = Starknet::chain_id(); let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::NoValidate)); - - let deploy_tx = DeployAccountTransaction { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, - }; - - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); + let deploy_tx = helper_create_deploy_account_tx(chain_id, *SALT, calldata, account_class_hash); + set_infinite_tokens::(&deploy_tx.contract_address); assert_ok!(Starknet::deploy_account(RuntimeOrigin::none(), deploy_tx.clone())); - assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), account_class_hash.0); assert_err!( Starknet::deploy_account(RuntimeOrigin::none(), deploy_tx), Error::::AccountAlreadyDeployed @@ -102,21 +122,17 @@ fn given_contract_run_deploy_account_tx_undeclared_then_it_fails() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let account_class_hash = get_account_class_hash(AccountType::V0(AccountTypeV0Inner::Argent)); - let transaction = DeployAccountTransaction { - class_hash: account_class_hash.into(), - constructor_calldata: vec![], - contract_address_salt: Felt252Wrapper::ZERO, - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, - }; - assert_err!( - Starknet::deploy_account(none_origin, transaction), - Error::::TransactionExecutionFailed + let deploy_tx = helper_create_deploy_account_tx( + chain_id, + ContractAddressSalt(StarkFelt::ZERO), + Calldata(Default::default()), + account_class_hash, ); + + assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); } @@ -126,14 +142,15 @@ fn given_contract_run_deploy_account_tx_fails_wrong_tx_version() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); - let transaction = - get_deploy_account_dummy(Felt252Wrapper::ZERO, *SALT, AccountType::V0(AccountTypeV0Inner::Argent)); + let deploy_tx = { + let tx = + get_deploy_account_dummy(Nonce(StarkFelt::ZERO), *SALT, AccountType::V0(AccountTypeV0Inner::Argent)); + deploy_v1_to_blockifier_deploy(tx, chain_id) + }; - assert_err!( - Starknet::deploy_account(none_origin, transaction), - Error::::TransactionExecutionFailed - ); + assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); } @@ -143,29 +160,41 @@ fn given_contract_run_deploy_account_openzeppelin_tx_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - let mut deploy_tx = DeployAccountTransaction { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + let tx_hash = tx.compute_hash(chain_id, false); + tx.signature = sign_message_hash(tx_hash); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + + DeployAccountTransaction::new( + starknet_api::transaction::DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) }; - let chain_id = Starknet::chain_id(); - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(chain_id, false); - deploy_tx.signature = sign_message_hash(tx_hash); - let address = deploy_tx.account_address().into(); - - set_infinite_tokens::(&address); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); + set_infinite_tokens::(&deploy_tx.contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); assert_ok!(Starknet::deploy_account(none_origin, deploy_tx)); - assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), account_class_hash.0); }); } @@ -175,21 +204,22 @@ fn given_contract_run_deploy_account_openzeppelin_with_incorrect_signature_then_ basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - let mut deploy_tx = DeployAccountTransaction { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + deploy_v1_to_blockifier_deploy(tx, chain_id) }; - deploy_tx.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; - let address = deploy_tx.account_address().into(); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); @@ -201,29 +231,41 @@ fn given_contract_run_deploy_account_argent_tx_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); - let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - - let mut deploy_tx = DeployAccountTransaction { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Argent)); + + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + let tx_hash = tx.compute_hash(chain_id, false); + tx.signature = sign_message_hash(tx_hash); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + + DeployAccountTransaction::new( + starknet_api::transaction::DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) }; - let chain_id = Starknet::chain_id(); - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(chain_id, false); - deploy_tx.signature = sign_message_hash(tx_hash); - - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Argent)); + set_infinite_tokens::(&deploy_tx.contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Argent)); assert_ok!(Starknet::deploy_account(none_origin, deploy_tx)); - assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), account_class_hash.0); }); } @@ -233,22 +275,22 @@ fn given_contract_run_deploy_account_argent_with_incorrect_signature_then_it_fai basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - - let mut deploy_tx = DeployAccountTransaction { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + let chain_id = Starknet::chain_id(); + let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::Argent)); + + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + deploy_v1_to_blockifier_deploy(tx, chain_id) }; - deploy_tx.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; - let address = deploy_tx.account_address().into(); - - set_signer(address, AccountType::V0(AccountTypeV0Inner::Argent)); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Argent)); assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); @@ -260,30 +302,42 @@ fn given_contract_run_deploy_account_braavos_tx_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let (proxy_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::BraavosProxy)); - let mut calldata: Vec<_> = calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(); - calldata.push(Felt252Wrapper::ONE); - calldata.push(Felt252Wrapper::from_hex_be(ACCOUNT_PUBLIC_KEY).unwrap()); - - let mut deploy_tx = DeployAccountTransaction { - max_fee: u64::MAX as u128, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata, - class_hash: proxy_class_hash.into(), - offset_version: false, + calldata.0.push(StarkFelt::ONE); + calldata.0.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: proxy_class_hash, + }; + let tx_hash = tx.compute_hash(chain_id, false); + tx.signature = sign_message_hash_braavos(tx_hash, StarkFelt::ZERO, &[StarkFelt::ZERO; 7]); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + + DeployAccountTransaction::new( + starknet_api::transaction::DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) }; - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(Starknet::chain_id(), false); - deploy_tx.signature = sign_message_hash_braavos(tx_hash, Felt252Wrapper::ZERO, &[Felt252Wrapper::ZERO; 7]); - - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Braavos)); + set_infinite_tokens::(&deploy_tx.contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Braavos)); assert_ok!(Starknet::deploy_account(none_origin, deploy_tx)); - assert_eq!(Starknet::contract_class_hash_by_address(address), proxy_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), proxy_class_hash.0); }); } @@ -293,46 +347,57 @@ fn given_contract_run_deploy_account_braavos_tx_works_whis_hardware_signer() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let (proxy_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::BraavosProxy)); - let mut calldata: Vec<_> = calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(); - calldata.push(Felt252Wrapper::ONE); - calldata.push(Felt252Wrapper::from_hex_be(ACCOUNT_PUBLIC_KEY).unwrap()); - - let mut deploy_tx = DeployAccountTransaction { - max_fee: u64::MAX as u128, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - contract_address_salt: *SALT, - constructor_calldata: calldata, - class_hash: proxy_class_hash.into(), - offset_version: false, + calldata.0.push(StarkFelt::ONE); + calldata.0.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: proxy_class_hash, + }; + let tx_hash = tx.compute_hash(chain_id, false); + // signer fields are hardware public key generated from some random private key + // it's possible to add only one additional secp256r1 signer + let signer_model = [ + StarkFelt::try_from("0x23fc01adbb70af88935aeaecde1240ea").unwrap(), /* signer_0= pk_x_uint256 + * low 128 bits */ + StarkFelt::try_from("0xea0cb2b3f76a88bba0d8dc7556c40df9").unwrap(), /* signer_1= pk_x_uint256 + * high 128 bits */ + StarkFelt::try_from("0x663b66d81aa5eed14537e814b02745c0").unwrap(), /* signer_2= pk_y_uint256 + * low 128 bits */ + StarkFelt::try_from("0x76d91b936d094b864af4cfaaeec89fb1").unwrap(), /* signer_3= pk_y_uint256 + * high 128 bits */ + StarkFelt::TWO, // type= SIGNER_TYPE_SECP256R1 + StarkFelt::ZERO, // reserved_0 + StarkFelt::ZERO, // reserved_1 + ]; + tx.signature = sign_message_hash_braavos(tx_hash, StarkFelt::ZERO, &signer_model); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + + DeployAccountTransaction::new( + starknet_api::transaction::DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) }; - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(Starknet::chain_id(), false); - - // signer fields are hardware public key generated from some random private key - // it's possible to add only one additional secp256r1 signer - let signer_model = [ - Felt252Wrapper::from_hex_be("0x23fc01adbb70af88935aeaecde1240ea").unwrap(), /* signer_0= pk_x_uint256 - * low 128 bits */ - Felt252Wrapper::from_hex_be("0xea0cb2b3f76a88bba0d8dc7556c40df9").unwrap(), /* signer_1= pk_x_uint256 - * high 128 bits */ - Felt252Wrapper::from_hex_be("0x663b66d81aa5eed14537e814b02745c0").unwrap(), /* signer_2= pk_y_uint256 - * low 128 bits */ - Felt252Wrapper::from_hex_be("0x76d91b936d094b864af4cfaaeec89fb1").unwrap(), /* signer_3= pk_y_uint256 - * high 128 bits */ - Felt252Wrapper::TWO, // type= SIGNER_TYPE_SECP256R1 - Felt252Wrapper::ZERO, // reserved_0 - Felt252Wrapper::ZERO, // reserved_1 - ]; - deploy_tx.signature = sign_message_hash_braavos(tx_hash, Felt252Wrapper::ZERO, &signer_model); - - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Braavos)); + set_infinite_tokens::(&deploy_tx.contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Braavos)); assert_ok!(Starknet::deploy_account(none_origin, deploy_tx)); - assert_eq!(Starknet::contract_class_hash_by_address(address), proxy_class_hash); + assert_eq!(Starknet::contract_class_hash_by_address(deploy_tx.contract_address), proxy_class_hash.0); }); } @@ -342,24 +407,25 @@ fn given_contract_run_deploy_account_braavos_with_incorrect_signature_then_it_fa basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let (proxy_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::BraavosProxy)); - let mut calldata = calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect::>(); - calldata.push(Felt252Wrapper::ZERO); - calldata.push(Felt252Wrapper::from_hex_be(ACCOUNT_PUBLIC_KEY).unwrap()); - - let deploy_tx = DeployAccountTransaction { - class_hash: proxy_class_hash.into(), - contract_address_salt: *SALT, - constructor_calldata: calldata, - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: [Felt252Wrapper::ZERO; 10].to_vec(), - offset_version: false, + calldata.0.push(StarkFelt::ZERO); + calldata.0.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + + let deploy_tx = { + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature([StarkFelt::ONE; 10].to_vec()), + contract_address_salt: *SALT, + constructor_calldata: calldata, + class_hash: proxy_class_hash, + }; + deploy_v1_to_blockifier_deploy(tx, chain_id) }; - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); - set_signer(address, AccountType::V0(AccountTypeV0Inner::Braavos)); + set_infinite_tokens::(&deploy_tx.contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Braavos)); assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); @@ -369,9 +435,11 @@ fn given_contract_run_deploy_account_braavos_with_incorrect_signature_then_it_fa fn test_verify_tx_longevity() { new_test_ext::().execute_with(|| { basic_test_setup(2); + let chain_id = Starknet::chain_id(); - let transaction = - get_deploy_account_dummy(Felt252Wrapper::ZERO, *SALT, AccountType::V0(AccountTypeV0Inner::NoValidate)); + let tx = + get_deploy_account_dummy(Nonce(StarkFelt::ZERO), *SALT, AccountType::V0(AccountTypeV0Inner::NoValidate)); + let transaction = deploy_v1_to_blockifier_deploy(tx, chain_id); let validate_result = Starknet::validate_unsigned(TransactionSource::InBlock, &crate::Call::deploy_account { transaction }); @@ -398,16 +466,17 @@ fn test_verify_nonce_in_unsigned_tx() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = - get_deploy_account_dummy(Felt252Wrapper::ZERO, *SALT, AccountType::V0(AccountTypeV0Inner::NoValidate)); + let chain_id = Starknet::chain_id(); + let tx = + get_deploy_account_dummy(Nonce(StarkFelt::ZERO), *SALT, AccountType::V0(AccountTypeV0Inner::NoValidate)); + let transaction = deploy_v1_to_blockifier_deploy(tx, chain_id); - let tx_sender = transaction.account_address().into(); let tx_source = TransactionSource::InBlock; let call = crate::Call::deploy_account { transaction }; assert!(Starknet::validate_unsigned(tx_source, &call).is_ok()); - set_nonce::(&tx_sender, &Nonce(StarkFelt::from(1u64))); + set_nonce::(&transaction.contract_address, &Nonce(StarkFelt::from(1u64))); assert_eq!( Starknet::validate_unsigned(tx_source, &call), diff --git a/crates/pallets/starknet/src/tests/erc20.rs b/crates/pallets/starknet/src/tests/erc20.rs index dd8e76dd1a..7bd2c22cb7 100644 --- a/crates/pallets/starknet/src/tests/erc20.rs +++ b/crates/pallets/starknet/src/tests/erc20.rs @@ -1,20 +1,23 @@ +use std::sync::Arc; + use blockifier::execution::contract_class::ContractClass; use frame_support::assert_ok; use lazy_static::lazy_static; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::InvokeTransactionV1; -use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::core::{ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; -use starknet_api::transaction::{Event as StarknetEvent, EventContent, EventData, EventKey, TransactionHash}; +use starknet_api::transaction::{ + Calldata, Event as StarknetEvent, EventContent, EventData, EventKey, Fee, InvokeTransactionV1, TransactionHash, + TransactionSignature, +}; use starknet_core::utils::get_selector_from_name; use super::mock::default_mock::*; use super::mock::*; use crate::tests::constants::{TOKEN_CONTRACT_CLASS_HASH, TRANSFER_SELECTOR_NAME}; -use crate::tests::utils::{build_transfer_invoke_transaction, get_contract_class}; -use crate::types::BuildTransferInvokeTransaction; +use crate::tests::utils::{build_transfer_invoke_transaction, get_contract_class, BuildTransferInvokeTransaction}; use crate::Config; lazy_static! { @@ -26,38 +29,36 @@ fn given_erc20_transfer_when_invoke_then_it_works() { new_test_ext::().execute_with(|| { basic_test_setup(1); let origin = RuntimeOrigin::none(); - let sender_account = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let felt_252_sender_account = sender_account.into(); + let sender_address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); // ERC20 is already declared for the fees. // Deploy ERC20 contract let deploy_transaction = InvokeTransactionV1 { - max_fee: u128::MAX, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - sender_address: felt_252_sender_account, - calldata: vec![ - felt_252_sender_account, // Simple contract address - Felt252Wrapper::from_hex_be("0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8") + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + sender_address, + calldata: Calldata(Arc::new(vec![ + sender_address.0.0, // Simple contract address + StarkFelt::try_from("0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8") .unwrap(), // deploy_contract selector - Felt252Wrapper::from_hex_be("0x9").unwrap(), // Calldata len - Felt252Wrapper::from_hex_be(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash - Felt252Wrapper::ONE, // Contract address salt - Felt252Wrapper::from_hex_be("0x6").unwrap(), // Constructor_calldata_len - Felt252Wrapper::from_hex_be("0xA").unwrap(), // Name - Felt252Wrapper::from_hex_be("0x1").unwrap(), // Symbol - Felt252Wrapper::from_hex_be("0x2").unwrap(), // Decimals - Felt252Wrapper::from_hex_be("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply low - Felt252Wrapper::from_hex_be("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply high - felt_252_sender_account, // recipient - ], - offset_version: false, + StarkFelt::try_from("0x9").unwrap(), // Calldata len + StarkFelt::try_from(TOKEN_CONTRACT_CLASS_HASH).unwrap(), // Class hash + StarkFelt::ONE, // Contract address salt + StarkFelt::try_from("0x6").unwrap(), // Constructor_calldata_len + StarkFelt::try_from("0xA").unwrap(), // Name + StarkFelt::try_from("0x1").unwrap(), // Symbol + StarkFelt::try_from("0x2").unwrap(), // Decimals + StarkFelt::try_from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply low + StarkFelt::try_from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").unwrap(), // Initial supply high + sender_address.0.0, // recipient + ])), }; let expected_erc20_address = StarkFelt::try_from("0x00dc58c1280862c95964106ef9eba5d9ed8c0c16d05883093e4540f22b829dff").unwrap(); let chain_id = Starknet::chain_id(); - let tx_hash = deploy_transaction.compute_hash::<::SystemHash>(chain_id, false); + let tx_hash = deploy_transaction.compute_hash(chain_id, false); assert_ok!(Starknet::invoke(origin.clone(), deploy_transaction.into())); @@ -98,7 +99,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() { .unwrap(), // Salt ]), }, - from_address: sender_account, + from_address: sender_address, }, events[1], ); @@ -108,7 +109,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() { Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap()).into(), )], data: EventData(vec![ - sender_account.0 .0, // From + sender_address.0 .0, // From StarkFelt::try_from("0x000000000000000000000000000000000000000000000000000000000000dead").unwrap(), // Sequencer address StarkFelt::try_from("0x00000000000000000000000000000000000000000000000000000000000197a8").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high @@ -124,16 +125,16 @@ fn given_erc20_transfer_when_invoke_then_it_works() { // TODO: use dynamic values to craft invoke transaction // Transfer some token let transfer_transaction = build_transfer_invoke_transaction(BuildTransferInvokeTransaction { - sender_address: felt_252_sender_account, - token_address: expected_erc20_address.into(), - recipient: Felt252Wrapper::from(16u128), - amount_low: Felt252Wrapper::from(15u128), - amount_high: Felt252Wrapper::ZERO, - nonce: Felt252Wrapper::ONE, + sender_address, + token_address: Felt252Wrapper::from(expected_erc20_address).into(), + recipient: Felt252Wrapper::from(16u128).into(), + amount_low: Felt252Wrapper::from(15u128).into(), + amount_high: Felt252Wrapper::ZERO.into(), + nonce: Felt252Wrapper::ONE.into(), }); let chain_id = Starknet::chain_id(); - let tx_hash = transfer_transaction.compute_hash::<::SystemHash>(chain_id, false); + let tx_hash = transfer_transaction.compute_hash(chain_id, false); // Also asserts that the deployment has been saved. assert_ok!(Starknet::invoke(origin, transfer_transaction)); @@ -205,7 +206,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() { StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), )], data: EventData(vec![ - sender_account.0 .0, // From + sender_address.0 .0, // From StarkFelt::try_from("0xdead").unwrap(), // Sequencer address StarkFelt::try_from("0xf014").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high diff --git a/crates/pallets/starknet/src/tests/fees_disabled.rs b/crates/pallets/starknet/src/tests/fees_disabled.rs index 9e0b558d9a..29ba8df25f 100644 --- a/crates/pallets/starknet/src/tests/fees_disabled.rs +++ b/crates/pallets/starknet/src/tests/fees_disabled.rs @@ -1,26 +1,34 @@ use frame_support::assert_ok; use mp_felt::Felt252Wrapper; -use mp_transactions::InvokeTransaction; -use starknet_api::core::{ContractAddress, EntryPointSelector, PatriciaKey}; +use mp_hashers::HasherT; +use mp_transactions::compute_hash::ComputeTransactionHash; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_api::transaction::Calldata; use super::constants::FEE_TOKEN_ADDRESS; -use super::mock::{default_mock, fees_disabled_mock, *}; -use super::utils::{build_get_balance_contract_call, build_transfer_invoke_transaction}; -use crate::types::BuildTransferInvokeTransaction; +use super::mock::*; +use super::utils::{ + build_get_balance_contract_call, build_transfer_invoke_transaction, BuildTransferInvokeTransaction, +}; +use crate::tests::mock::setup_mock::default_mock::*; +use crate::Config; #[test] fn given_default_runtime_with_fees_enabled_txn_deducts_fee_token() { new_test_ext::().execute_with(|| { default_mock::basic_test_setup(2); let origin = default_mock::RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); let (initial_balance_low, initial_balance_high) = get_balance_default_mock(address); // transfer to zero fee token so that the only change in balance can happen because of fees - assert_ok!(default_mock::Starknet::invoke(origin, build_invoke_transaction(address))); + assert_ok!(default_mock::Starknet::invoke( + origin, + build_invoke_transaction::<::SystemHash>(chain_id, address) + )); let (final_balance_low, final_balance_high) = get_balance_default_mock(address); // Check that the balance has changed because fees is reduced @@ -34,12 +42,16 @@ fn given_default_runtime_with_fees_disabled_txn_does_not_deduct_fee_token() { new_test_ext::().execute_with(|| { fees_disabled_mock::basic_test_setup(2); let origin = fees_disabled_mock::RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); let address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); let (initial_balance_low, initial_balance_high) = get_balance_fees_disabled_mock(address); // transfer to zero fee token so that the only change in balance can happen because of fees - assert_ok!(fees_disabled_mock::Starknet::invoke(origin, build_invoke_transaction(address))); + assert_ok!(fees_disabled_mock::Starknet::invoke( + origin, + build_invoke_transaction::<::SystemHash>(chain_id, address) + )); let (final_balance_low, final_balance_high) = get_balance_fees_disabled_mock(address); // Check that the balance hasn't changed @@ -48,15 +60,21 @@ fn given_default_runtime_with_fees_disabled_txn_does_not_deduct_fee_token() { }); } -fn build_invoke_transaction(address: ContractAddress) -> InvokeTransaction { - build_transfer_invoke_transaction(BuildTransferInvokeTransaction { - sender_address: address.into(), - token_address: Felt252Wrapper::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), - recipient: address.into(), - amount_low: Felt252Wrapper::ZERO, - amount_high: Felt252Wrapper::ZERO, - nonce: Felt252Wrapper::ZERO, - }) +fn build_invoke_transaction( + chain_id: Felt252Wrapper, + address: ContractAddress, +) -> blockifier::transaction::transactions::InvokeTransaction { + let tx = build_transfer_invoke_transaction(BuildTransferInvokeTransaction { + sender_address: address, + token_address: ContractAddress(PatriciaKey(StarkFelt::try_from(FEE_TOKEN_ADDRESS).unwrap())), + recipient: address, + amount_low: StarkFelt::ZERO, + amount_high: StarkFelt::ZERO, + nonce: Nonce(StarkFelt::ZERO), + }); + let tx_hash = tx.compute_hash::(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } fn get_balance_default_mock(account_address: ContractAddress) -> (Felt252Wrapper, Felt252Wrapper) { diff --git a/crates/pallets/starknet/src/tests/mod.rs b/crates/pallets/starknet/src/tests/mod.rs index dfc2d3ad7b..dc536f95f0 100644 --- a/crates/pallets/starknet/src/tests/mod.rs +++ b/crates/pallets/starknet/src/tests/mod.rs @@ -1,8 +1,16 @@ +use std::sync::Arc; + +use blockifier::abi::abi_utils::get_fee_token_var_address; +use blockifier::abi::sierra_types::next_storage_key; use blockifier::state::state_api::State; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use starknet_api::core::{ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, DeclareTransaction, DeclareTransactionV0V1, DeployAccountTransactionV1, Fee, + InvokeTransactionV1, TransactionSignature, +}; use self::mock::default_mock::{MockRuntime, Starknet}; use self::mock::{get_account_address, AccountType}; @@ -33,203 +41,208 @@ mod constants; mod mock; mod utils; +const MAX_FEE: Fee = Fee(u64::MAX as u128); + // ref: https://github.com/tdelabro/blockifier/blob/no_std-support/crates/blockifier/feature_contracts/account_without_validations.cairo -pub fn get_invoke_dummy(nonce: Felt252Wrapper) -> InvokeTransactionV1 { - let signature = vec![ - Felt252Wrapper::from_hex_be("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), - Felt252Wrapper::from_hex_be("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), - ]; - let sender_address = Felt252Wrapper::from_hex_be(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap(); - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ - Felt252Wrapper::from_hex_be("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector for the `with_arg` external */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } +pub fn get_invoke_dummy(nonce: Nonce) -> InvokeTransactionV1 { + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap())); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector for the `with_arg` external */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } // ref: https://github.com/argentlabs/argent-contracts-starknet/blob/develop/contracts/account/ArgentAccount.cairo fn get_invoke_argent_dummy() -> InvokeTransactionV1 { - let sender_address = - Felt252Wrapper::from_hex_be("0x02e63de215f650e9d7e2313c6e9ed26b4f920606fb08576b1663c21a7c4a28c5").unwrap(); - let nonce = Felt252Wrapper::ZERO; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* to */ - Felt252Wrapper::from_hex_be("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data_offset */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - ]; - - InvokeTransactionV1 { - max_fee: u64::MAX as u128, - signature: vec![], - nonce, - sender_address, - calldata, - offset_version: false, - } + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x02e63de215f650e9d7e2313c6e9ed26b4f920606fb08576b1663c21a7c4a28c5").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data_offset */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature: TransactionSignature(vec![]), nonce, sender_address, calldata } } // ref: https://github.com/myBraavos/braavos-account-cairo/blob/develop/src/account/Account.cairo fn get_invoke_braavos_dummy() -> InvokeTransactionV1 { - let signature = vec![ - Felt252Wrapper::from_hex_be("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), - Felt252Wrapper::from_hex_be("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), - ]; - let sender_address = - Felt252Wrapper::from_hex_be("0x05ef3fba22df259bf84890945352df711bcc9a4e3b6858cb93e9c90d053cf122").unwrap(); - let nonce = Felt252Wrapper::ZERO; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* to */ - Felt252Wrapper::from_hex_be("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data_offset */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x05ef3fba22df259bf84890945352df711bcc9a4e3b6858cb93e9c90d053cf122").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data_offset */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } // ref: https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/token/erc20/IERC20.cairo fn get_invoke_emit_event_dummy() -> InvokeTransactionV1 { - let signature = vec![ - Felt252Wrapper::from_hex_be("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), - Felt252Wrapper::from_hex_be("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), - ]; - let sender_address = - Felt252Wrapper::from_hex_be("0x01a3339ec92ac1061e3e0f8e704106286c642eaf302e94a582e5f95ef5e6b4d0").unwrap(); - let nonce = Felt252Wrapper::ZERO; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* to */ - Felt252Wrapper::from_hex_be("0x00966af5d72d3975f70858b044c77785d3710638bbcebbd33cc7001a91025588").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* amount */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x01a3339ec92ac1061e3e0f8e704106286c642eaf302e94a582e5f95ef5e6b4d0").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00966af5d72d3975f70858b044c77785d3710638bbcebbd33cc7001a91025588").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* amount */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } // ref: https://github.com/tdelabro/blockifier/blob/no_std-support/crates/blockifier/feature_contracts/account_without_validations.cairo fn get_invoke_nonce_dummy() -> InvokeTransactionV1 { - let signature = vec![ - Felt252Wrapper::from_hex_be("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), - Felt252Wrapper::from_hex_be("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), - ]; - let sender_address = Felt252Wrapper::from_hex_be(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap(); - let nonce = Felt252Wrapper::ONE; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ - Felt252Wrapper::from_hex_be("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x00f513fe663ffefb9ad30058bb2d2f7477022b149a0c02fb63072468d3406168").unwrap(), + StarkFelt::try_from("0x02e29e92544d31c03e89ecb2005941c88c28b4803a3647a7834afda12c77f096").unwrap(), + ]); + let sender_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap())); + let nonce = Nonce(StarkFelt::ONE); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } // ref: https://github.com/keep-starknet-strange/madara/blob/main/cairo-contracts/src/accounts/NoValidateAccount.cairo fn get_storage_read_write_dummy() -> InvokeTransactionV1 { - let signature = vec![]; - let sender_address = Felt252Wrapper::from_hex_be(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap(); - let nonce = Felt252Wrapper::ZERO; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ - Felt252Wrapper::from_hex_be("0x03b097c62d3e4b85742aadd0dfb823f96134b886ec13bda57b68faf86f294d97").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000002").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata[1] */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } + let signature = TransactionSignature(vec![]); + let sender_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap())); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* contract_address */ + StarkFelt::try_from("0x03b097c62d3e4b85742aadd0dfb823f96134b886ec13bda57b68faf86f294d97").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000002").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata[1] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } // ref: https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/account/IAccount.cairo fn get_invoke_openzeppelin_dummy() -> InvokeTransactionV1 { - let signature = vec![ - Felt252Wrapper::from_hex_be("0x028ef1ae6c37314bf9df65663db1cf68f95d67c4b4cf7f6590654933a84912b0").unwrap(), - Felt252Wrapper::from_hex_be("0x0625aae99c58b18e5161c719fef0f99579c6468ca6c1c866f9b2b968a5447e4").unwrap(), - ]; - let sender_address = - Felt252Wrapper::from_hex_be("0x06e2616a2dceff4355997369246c25a78e95093df7a49e5ca6a06ce1544ffd50").unwrap(); - let nonce = Felt252Wrapper::ZERO; - let calldata = vec![ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), /* to */ - Felt252Wrapper::from_hex_be("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data offset */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data length */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ - Felt252Wrapper::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ - ]; - - InvokeTransactionV1 { max_fee: u64::MAX as u128, signature, nonce, sender_address, calldata, offset_version: false } + let signature = TransactionSignature(vec![ + StarkFelt::try_from("0x028ef1ae6c37314bf9df65663db1cf68f95d67c4b4cf7f6590654933a84912b0").unwrap(), + StarkFelt::try_from("0x0625aae99c58b18e5161c719fef0f99579c6468ca6c1c866f9b2b968a5447e4").unwrap(), + ]); + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x06e2616a2dceff4355997369246c25a78e95093df7a49e5ca6a06ce1544ffd50").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let calldata = Calldata(Arc::new(vec![ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* call_array_len */ + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), // to + StarkFelt::try_from("0x00e7def693d16806ca2a2f398d8de5951344663ba77f340ed7a958da731872fc").unwrap(), /* selector */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000000").unwrap(), /* data offset */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* data length */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000001").unwrap(), /* calldata_len */ + StarkFelt::try_from("0x0000000000000000000000000000000000000000000000000000000000000019").unwrap(), /* calldata[0] */ + ])); + + InvokeTransactionV1 { max_fee: MAX_FEE, signature, nonce, sender_address, calldata } } /// Returns a dummy declare transaction for the given account type. /// The declared class hash is a ERC20 contract, class hash calculated /// with starkli. -pub fn get_declare_dummy( - chain_id: Felt252Wrapper, - nonce: Felt252Wrapper, - account_type: AccountType, -) -> DeclareTransaction { +pub fn get_declare_dummy(chain_id: Felt252Wrapper, nonce: Nonce, account_type: AccountType) -> DeclareTransaction { let account_addr = get_account_address(None, account_type); let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4").unwrap(); + ClassHash(StarkFelt::try_from("0x372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4").unwrap()); - let mut tx = DeclareTransactionV1 { - max_fee: u64::MAX as u128, - signature: vec![], + let mut tx = DeclareTransaction::V1(DeclareTransactionV0V1 { + max_fee: MAX_FEE, + signature: TransactionSignature(vec![]), nonce, class_hash: erc20_class_hash, sender_address: account_addr.into(), - offset_version: false, - }; + }); let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, false); - let signature = sign_message_hash(tx_hash); - tx.signature = signature; - tx.into() + match tx { + DeclareTransaction::V1(mut tx) => tx.signature = signature, + _ => unreachable!(), + } + + tx } /// Returns a dummy deploy account transaction for the given salt and account type pub fn get_deploy_account_dummy( - nonce: Felt252Wrapper, - salt: Felt252Wrapper, + nonce: Nonce, + contract_address_salt: ContractAddressSalt, account_type: AccountType, -) -> DeployAccountTransaction { +) -> DeployAccountTransactionV1 { let (account_class_hash, calldata) = account_helper(account_type); - DeployAccountTransaction { - max_fee: u64::MAX as u128, - signature: vec![], + DeployAccountTransactionV1 { + max_fee: Fee(u64::MAX as u128), + signature: TransactionSignature(vec![]), nonce, - contract_address_salt: salt, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + contract_address_salt, + constructor_calldata: calldata, + class_hash: account_class_hash, } } /// Sets the balance of the given address to infinite. pub fn set_infinite_tokens(contract_address: &ContractAddress) { let fee_token_addresses = Starknet::fee_token_addresses(); - let (low_key, high_key) = get_erc20_balance_var_addresses(contract_address).unwrap(); + let balance_key_low = get_fee_token_var_address(fee_token_addresses.eth_fee_token_address); + let balance_key_high = next_storage_key(&balance_key_low).expect("Cannot get balance high key."); + let mut state_adapter = BlockifierStateAdapter::::default(); - state_adapter.set_storage_at(fee_token_addresses.eth_fee_token_address, low_key, StarkFelt::from(u64::MAX as u128)); state_adapter.set_storage_at( fee_token_addresses.eth_fee_token_address, - high_key, + balance_key_low, + StarkFelt::from(u64::MAX as u128), + ); + state_adapter.set_storage_at( + fee_token_addresses.eth_fee_token_address, + balance_key_high, StarkFelt::from(u64::MAX as u128), ); } diff --git a/crates/pallets/starknet/src/tests/query_tx.rs b/crates/pallets/starknet/src/tests/query_tx.rs index e3b6bc1278..71ef05e83a 100644 --- a/crates/pallets/starknet/src/tests/query_tx.rs +++ b/crates/pallets/starknet/src/tests/query_tx.rs @@ -1,7 +1,7 @@ +use blockifier::transaction::account_transaction::AccountTransaction; use frame_support::{assert_err, assert_ok}; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::UserTransaction; use super::mock::default_mock::*; use super::mock::new_test_ext; @@ -14,11 +14,11 @@ fn estimates_tx_fee_successfully_no_validate() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let tx_1: mp_transactions::InvokeTransactionV1 = get_storage_read_write_dummy(); - let tx_1 = UserTransaction::Invoke(tx_1.into()); + let tx_1 = get_storage_read_write_dummy(); + let tx_1 = AccountTransaction::Invoke(tx_1.into()); let tx_2 = get_invoke_dummy(Felt252Wrapper::ONE); - let tx_2 = UserTransaction::Invoke(tx_2.into()); + let tx_2 = AccountTransaction::Invoke(tx_2.into()); let txs = vec![tx_1, tx_2]; @@ -41,7 +41,7 @@ fn estimates_tx_fee_with_query_version() { let tx = get_invoke_dummy(Felt252Wrapper::ZERO); let pre_storage = Starknet::pending().len(); - let tx = UserTransaction::Invoke(tx.into()); + let tx = AccountTransaction::Invoke(tx.into()); let tx_vec = vec![tx]; @@ -61,7 +61,7 @@ fn executable_tx_should_not_be_estimable() { let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, false); tx.signature = sign_message_hash(tx_hash); - let tx_vec = vec![UserTransaction::Invoke(tx.clone().into())]; + let tx_vec = vec![AccountTransaction::Invoke(tx.clone().into())]; // it should be valid for estimate calls assert_ok!(Starknet::estimate_fee(tx_vec)); @@ -82,7 +82,7 @@ fn query_tx_should_not_be_executable() { let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, true); tx.signature = sign_message_hash(tx_hash); - let tx_vec = vec![UserTransaction::Invoke(tx.clone().into())]; + let tx_vec = vec![AccountTransaction::Invoke(tx.clone().into())]; // it should be valid for estimate calls assert_ok!(Starknet::estimate_fee(tx_vec)); diff --git a/crates/pallets/starknet/src/tests/re_execute_transactions.rs b/crates/pallets/starknet/src/tests/re_execute_transactions.rs index 78376a3cbf..7dd9ed9859 100644 --- a/crates/pallets/starknet/src/tests/re_execute_transactions.rs +++ b/crates/pallets/starknet/src/tests/re_execute_transactions.rs @@ -1,81 +1,116 @@ +use std::sync::Arc; + +use blockifier::execution::contract_class::ClassInfo; use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::transaction_execution::Transaction; use blockifier::transaction::transactions::ExecutableTransaction; use mp_felt::Felt252Wrapper; -use starknet_api::core::{ContractAddress, Nonce}; -use starknet_api::transaction::Fee; +use mp_transactions::compute_hash::ComputeTransactionHash; +use starknet_api::core::{ + calculate_contract_address, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce, PatriciaKey, +}; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{Calldata, ContractAddressSalt, Fee, TransactionSignature, TransactionVersion}; use super::mock::default_mock::*; use super::mock::*; use crate::tests::utils::get_contract_class; use crate::tests::{constants, get_declare_dummy, get_invoke_dummy, set_infinite_tokens}; -use crate::types::CasmClassHash; use crate::Config; #[test] fn re_execute_tx_ok() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let invoke_sender_address: ContractAddress = - Felt252Wrapper::from_hex_be(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap().into(); + let invoke_sender_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(constants::BLOCKIFIER_ACCOUNT_ADDRESS).unwrap())); let chain_id = Starknet::chain_id(); // Deploy // TEST ACCOUNT CONTRACT // - ref testnet tx(0x0751b4b5b95652ad71b1721845882c3852af17e2ed0c8d93554b5b292abb9810) - let salt = - Felt252Wrapper::from_hex_be("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap(); + let salt = StarkFelt::try_from("0x03b37cbe4e9eac89d54c5f7cc6329a63a63e8c8db2bf936f981041e086752463").unwrap(); let (account_class_hash, calldata) = account_helper(AccountType::V0(AccountTypeV0Inner::NoValidate)); - let deploy_tx = DeployAccountTransaction { - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - contract_address_salt: salt, - constructor_calldata: calldata.0.iter().map(|e| Felt252Wrapper::from(*e)).collect(), - class_hash: account_class_hash.into(), - offset_version: false, + let deploy_tx = { + use starknet_api::transaction::{DeployAccountTransaction, DeployAccountTransactionV1}; + + let tx = DeployAccountTransactionV1 { + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), + contract_address_salt: ContractAddressSalt(salt), + constructor_calldata: calldata, + class_hash: account_class_hash, + }; + + let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, false); + let contract_address = calculate_contract_address( + tx.contract_address_salt, + tx.class_hash, + &tx.constructor_calldata, + Default::default(), + ) + .unwrap(); + blockifier::transaction::transactions::DeployAccountTransaction::new( + DeployAccountTransaction::V1(tx), + tx_hash, + contract_address, + ) }; - let address = deploy_tx.account_address().into(); - set_infinite_tokens::(&address); + set_infinite_tokens::(&deploy_tx.contract_address); // Declare - - let declare_tx = - get_declare_dummy(chain_id, Felt252Wrapper::ZERO, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - let erc20_class_hash: CasmClassHash = - Felt252Wrapper::from_hex_be("0x372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4") - .unwrap() - .into(); + let erc20_class_hash = CompiledClassHash( + StarkFelt::try_from("0x372ee6669dc86563007245ed7343d5180b96221ce28f44408cff2898038dbd4").unwrap(), + ); let erc20_class = get_contract_class("ERC20.json", 0); - let contract_address = - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(); - let from_address = Felt252Wrapper::from_hex_be("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), + )); + let from_address = StarkFelt::try_from("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); + let declare_tx = { + let declare_tx = + get_declare_dummy(chain_id, Nonce(StarkFelt::ZERO), AccountType::V0(AccountTypeV0Inner::Openzeppelin)); + let tx_hash = declare_tx.compute_hash::<::SystemHash>(chain_id, false); + blockifier::transaction::transactions::DeclareTransaction::new( + declare_tx, + tx_hash, + ClassInfo { contract_class: erc20_class, sierra_program_length: usize::MAX, abi_length: usize::MAX }, + ) + .unwrap() + }; // Handle l1 message - - let handle_l1_tx = HandleL1MessageTransaction { - nonce: 1, + let handle_l1_tx = { + let tx= starknet_api::transaction::L1HandlerTransaction { + nonce: Nonce(StarkFelt::ONE), contract_address, - entry_point_selector: Felt252Wrapper::from_hex_be( + entry_point_selector: EntryPointSelector(StarkFelt::try_from( "0x014093c40d95d0a3641c087f7d48d55160e1a58bc7c07b0d2323efeeb3087269", // test_l1_handler_store_under_caller_address ) - .unwrap(), - calldata: vec![ + .unwrap()), + calldata: Calldata(Arc::new(vec![ from_address, - Felt252Wrapper::from_hex_be("0x1").unwrap(), // value - ], + StarkFelt::ONE, // value + ])), + version: TransactionVersion(StarkFelt::ZERO), + }; + let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, false); + blockifier::transaction::transactions::L1HandlerTransaction { tx, tx_hash, paid_fee_on_l1: Fee(10) } }; let txs = vec![ - Transaction::AccountTransaction(AccountTransaction::Invoke(get_invoke_dummy(Felt252Wrapper::ZERO).into())), - Transaction::AccountTransaction(AccountTransaction::Invoke(get_invoke_dummy(Felt252Wrapper::ONE).into())), - Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx, erc20_class)), + Transaction::AccountTransaction(AccountTransaction::Invoke( + get_invoke_dummy(Nonce(StarkFelt::ZERO)).into(), + )), + Transaction::AccountTransaction(AccountTransaction::Invoke(get_invoke_dummy(Nonce(StarkFelt::ONE)).into())), + Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx)), Transaction::AccountTransaction(AccountTransaction::DeployAccount(deploy_tx)), - Transaction::L1HandlerTransaction(handle_l1_tx, Fee(10)), + Transaction::L1HandlerTransaction(handle_l1_tx), ]; // Call the function we want to test @@ -83,7 +118,7 @@ fn re_execute_tx_ok() { // Storage changes have been reverted assert_eq!(Starknet::nonce(invoke_sender_address), Nonce(Felt252Wrapper::ZERO.into())); - assert_eq!(Starknet::contract_class_by_class_hash(erc20_class_hash), None); + assert_eq!(Starknet::contract_class_by_class_hash(erc20_class_hash.0), None); // All txs are there assert_eq!(res.len(), 5); @@ -91,11 +126,9 @@ fn re_execute_tx_ok() { let first_invoke_tx_info = match txs.get(0).unwrap() { Transaction::AccountTransaction(AccountTransaction::Invoke(invoke_tx)) => { let mut state = Starknet::init_cached_state(); - let tx_info = AccountTransaction::Invoke( - invoke_tx.into_executable::<::SystemHash>(chain_id, false), - ) - .execute(&mut state, &Starknet::get_block_context(), true, true) - .unwrap(); + let tx_info = AccountTransaction::Invoke(*invoke_tx) + .execute(&mut state, &Starknet::get_block_context(), true, true) + .unwrap(); (tx_info, state.to_state_diff()) } _ => unreachable!(), @@ -104,26 +137,20 @@ fn re_execute_tx_ok() { let second_invoke_tx_info = match txs.get(1).unwrap() { Transaction::AccountTransaction(AccountTransaction::Invoke(invoke_tx)) => { let mut state = Starknet::init_cached_state(); - let tx_info = AccountTransaction::Invoke( - invoke_tx.into_executable::<::SystemHash>(chain_id, false), - ) - .execute(&mut state, &Starknet::get_block_context(), true, true) - .unwrap(); + let tx_info = AccountTransaction::Invoke(*invoke_tx) + .execute(&mut state, &Starknet::get_block_context(), true, true) + .unwrap(); (tx_info, state.to_state_diff()) } _ => unreachable!(), }; assert_eq!(res[1], second_invoke_tx_info); let declare_tx_info = match txs.get(2).unwrap() { - Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx, cc)) => { + Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx)) => { let mut state = Starknet::init_cached_state(); - let tx_info = AccountTransaction::Declare( - declare_tx - .try_into_executable::<::SystemHash>(chain_id, cc.clone(), false) - .unwrap(), - ) - .execute(&mut state, &Starknet::get_block_context(), true, true) - .unwrap(); + let tx_info = AccountTransaction::Declare(*declare_tx) + .execute(&mut state, &Starknet::get_block_context(), true, true) + .unwrap(); (tx_info, state.to_state_diff()) } _ => unreachable!(), @@ -132,23 +159,18 @@ fn re_execute_tx_ok() { let deploy_account_tx_info = match txs.get(3).unwrap() { Transaction::AccountTransaction(AccountTransaction::DeployAccount(deploy_account_tx)) => { let mut state = Starknet::init_cached_state(); - let tx_info = AccountTransaction::DeployAccount( - deploy_account_tx.into_executable::<::SystemHash>(chain_id, false), - ) - .execute(&mut state, &Starknet::get_block_context(), true, true) - .unwrap(); + let tx_info = AccountTransaction::DeployAccount(*deploy_account_tx) + .execute(&mut state, &Starknet::get_block_context(), true, true) + .unwrap(); (tx_info, state.to_state_diff()) } _ => unreachable!(), }; assert_eq!(res[3], deploy_account_tx_info); let handle_l1_message_tx_info = match txs.get(4).unwrap() { - Transaction::L1HandlerTransaction(l1_tx, fee) => { + Transaction::L1HandlerTransaction(l1_tx) => { let mut state = Starknet::init_cached_state(); - let tx_info = l1_tx - .into_executable::<::SystemHash>(chain_id, *fee, false) - .execute(&mut state, &Starknet::get_block_context(), true, true) - .unwrap(); + let tx_info = l1_tx.execute(&mut state, &Starknet::get_block_context(), true, true).unwrap(); (tx_info, state.to_state_diff()) } _ => unreachable!(), diff --git a/crates/pallets/starknet/src/tests/utils.rs b/crates/pallets/starknet/src/tests/utils.rs index 617f579737..8f5e615364 100644 --- a/crates/pallets/starknet/src/tests/utils.rs +++ b/crates/pallets/starknet/src/tests/utils.rs @@ -7,14 +7,15 @@ use blockifier::execution::contract_class::ContractClass; use mp_felt::Felt252Wrapper; use mp_hashers::pedersen::PedersenHasher; use mp_hashers::HasherT; -use starknet_api::core::EntryPointSelector; -use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{Calldata, Fee, InvokeTransaction, InvokeTransactionV1, TransactionSignature}; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::hash::{StarkFelt, StarkHash}; +use starknet_api::transaction::{ + Calldata, Fee, InvokeTransaction, InvokeTransactionV1, TransactionHash, TransactionSignature, +}; use starknet_crypto::{sign, FieldElement}; use super::constants::{ACCOUNT_PRIVATE_KEY, K}; use crate::genesis_loader::read_contract_class_from_json; -use crate::types::BuildTransferInvokeTransaction; pub fn get_contract_class(resource_path: &str, version: u8) -> ContractClass { let cargo_dir = String::from(env!("CARGO_MANIFEST_DIR")); @@ -30,10 +31,10 @@ pub fn get_contract_class(resource_path: &str, version: u8) -> ContractClass { } pub fn sign_message_hash_braavos( - tx_hash: Felt252Wrapper, - actual_impl_hash: Felt252Wrapper, - signer_model: &[Felt252Wrapper; 7], -) -> Vec { + tx_hash: TransactionHash, + actual_impl_hash: StarkHash, + signer_model: &[StarkFelt; 7], +) -> TransactionSignature { // struct SignerModel { // signer_0: felt, // signer_1: felt, @@ -43,44 +44,58 @@ pub fn sign_message_hash_braavos( // reserved_0: felt, // reserved_1: felt, // } - let mut elements = vec![tx_hash.0, actual_impl_hash.0]; - elements.extend_from_slice(&signer_model.iter().map(|e| e.0).collect::>()); + let mut elements: Vec = + vec![Felt252Wrapper::from(tx_hash).into(), Felt252Wrapper::from(actual_impl_hash).into()]; + elements.extend_from_slice( + &signer_model.iter().map(|e| Felt252Wrapper::from(*e).into()).collect::>(), + ); let braavos_hash = PedersenHasher::compute_hash_on_elements(&elements); - let mut signatures = sign_message_hash(Felt252Wrapper(braavos_hash)); - signatures.push(actual_impl_hash); - signatures.extend_from_slice(signer_model); + let mut signatures = sign_message_hash(Felt252Wrapper(braavos_hash).into()); + signatures.0.push(actual_impl_hash); + signatures.0.extend_from_slice(signer_model); signatures } -pub fn sign_message_hash(hash: Felt252Wrapper) -> Vec { +pub fn sign_message_hash(hash: TransactionHash) -> TransactionSignature { let signature = sign( &FieldElement::from_str(ACCOUNT_PRIVATE_KEY).unwrap(), - &FieldElement::from(hash), + &Felt252Wrapper::from(hash).into(), &FieldElement::from_str(K).unwrap(), ) .unwrap(); - vec![signature.r.into(), signature.s.into()] + + TransactionSignature(vec![Felt252Wrapper(signature.r).into(), Felt252Wrapper(signature.s).into()]) } pub fn build_transfer_invoke_transaction(request: BuildTransferInvokeTransaction) -> InvokeTransaction { InvokeTransaction::V1(InvokeTransactionV1 { max_fee: Fee(u128::MAX), signature: TransactionSignature(vec![]), - nonce: request.nonce.into(), - sender_address: request.sender_address.into(), + nonce: request.nonce, + sender_address: request.sender_address, calldata: Calldata(Arc::new(vec![ - request.token_address.into(), // Token address + request.token_address.0.0, // Token address StarkFelt::try_from("0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e").unwrap(), /* transfer * selector */ - StarkFelt::THREE, // Calldata len - request.recipient.into(), // recipient - request.amount_low.into(), // initial supply low - request.amount_high.into(), // initial supply high + StarkFelt::THREE, // Calldata len + request.recipient.0.0, // recipient + request.amount_low, // initial supply low + request.amount_high, // initial supply high ])), }) } +/// Build invoke transaction for transfer utils +pub struct BuildTransferInvokeTransaction { + pub sender_address: ContractAddress, + pub token_address: ContractAddress, + pub recipient: ContractAddress, + pub amount_low: StarkFelt, + pub amount_high: StarkFelt, + pub nonce: Nonce, +} + pub fn build_get_balance_contract_call(account_address: StarkFelt) -> (EntryPointSelector, Calldata) { let balance_of_selector = EntryPointSelector( StarkFelt::try_from("0x02e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e").unwrap(), diff --git a/crates/pallets/starknet/src/types.rs b/crates/pallets/starknet/src/types.rs index 781b7c32b3..04a180bc2a 100644 --- a/crates/pallets/starknet/src/types.rs +++ b/crates/pallets/starknet/src/types.rs @@ -6,6 +6,7 @@ use mp_felt::Felt252Wrapper; use sp_core::ConstU32; use sp_std::vec::Vec; use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::hash::StarkHash; use starknet_api::state::StorageKey; use starknet_api::transaction::{Event, Fee, MessageToL1, TransactionHash}; @@ -20,9 +21,9 @@ pub type ContractClassMapping = HashMap; /// Type wrapper for a storage slot. pub type StorageSlot = (StorageKey, Felt252Wrapper); -pub type CasmClassHash = ClassHash; -pub type SierraClassHash = ClassHash; -pub type SierraOrCasmClassHash = ClassHash; +pub type CasmClassHash = StarkHash; +pub type SierraClassHash = StarkHash; +pub type SierraOrCasmClassHash = StarkHash; /// Declare Transaction Output #[derive(Clone, Debug, PartialEq, Eq, parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)] @@ -34,16 +35,6 @@ pub struct DeployAccountTransactionOutput { pub contract_address: ContractAddress, } -/// Build invoke transaction for transfer utils -pub struct BuildTransferInvokeTransaction { - pub sender_address: Felt252Wrapper, - pub token_address: Felt252Wrapper, - pub recipient: Felt252Wrapper, - pub amount_low: Felt252Wrapper, - pub amount_high: Felt252Wrapper, - pub nonce: Felt252Wrapper, -} - #[derive(Clone, Debug, PartialEq, Eq, parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)] #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] pub struct TransactionOutput { diff --git a/crates/primitives/transactions/Cargo.toml b/crates/primitives/transactions/Cargo.toml index 4928364331..e3e695d574 100644 --- a/crates/primitives/transactions/Cargo.toml +++ b/crates/primitives/transactions/Cargo.toml @@ -22,6 +22,8 @@ starknet-crypto = { workspace = true, features = ["alloc"] } starknet-ff = { workspace = true, features = ["alloc"] } starknet_api = { workspace = true } indexmap = { workspace = true } +sha3 = { workspace = true } +sp-core = { workspace = true } # Optional (client) cairo-lang-starknet-classes = { workspace = true, optional = true } diff --git a/crates/primitives/transactions/src/compute_hash.rs b/crates/primitives/transactions/src/compute_hash.rs index ff00758fcc..faa62c82b7 100644 --- a/crates/primitives/transactions/src/compute_hash.rs +++ b/crates/primitives/transactions/src/compute_hash.rs @@ -1,6 +1,9 @@ use alloc::vec::Vec; +use blockifier::transaction::account_transaction::AccountTransaction; use mp_felt::Felt252Wrapper; +use mp_hashers::pedersen::PedersenHasher; +use mp_hashers::poseidon::PoseidonHasher; use mp_hashers::HasherT; use starknet_api::core::calculate_contract_address; use starknet_api::data_availability::DataAvailabilityMode; @@ -23,7 +26,7 @@ const L1_GAS: &[u8] = b"L1_GAS"; const L2_GAS: &[u8] = b"L2_GAS"; pub trait ComputeTransactionHash { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash; + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash; } fn convert_calldata(calldata: Calldata) -> Vec { @@ -58,7 +61,7 @@ fn prepare_data_availability_modes( } impl ComputeTransactionHash for InvokeTransactionV0 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(INVOKE_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET } else { FieldElement::ZERO }; let contract_address = Felt252Wrapper::from(self.contract_address).into(); @@ -66,7 +69,7 @@ impl ComputeTransactionHash for InvokeTransactionV0 { let calldata_hash = compute_hash_on_elements(&convert_calldata(self.calldata.clone())); let max_fee = FieldElement::from(self.max_fee.0); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, contract_address, @@ -80,7 +83,7 @@ impl ComputeTransactionHash for InvokeTransactionV0 { } impl ComputeTransactionHash for InvokeTransactionV1 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(INVOKE_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::ONE } else { FieldElement::ONE }; let sender_address = Felt252Wrapper::from(self.sender_address).into(); @@ -89,7 +92,7 @@ impl ComputeTransactionHash for InvokeTransactionV1 { let max_fee = FieldElement::from(self.max_fee.0); let nonce = Felt252Wrapper::from(self.nonce.0).into(); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, sender_address, @@ -104,7 +107,7 @@ impl ComputeTransactionHash for InvokeTransactionV1 { } impl ComputeTransactionHash for InvokeTransactionV3 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(INVOKE_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::THREE } else { FieldElement::THREE }; @@ -130,7 +133,7 @@ impl ComputeTransactionHash for InvokeTransactionV3 { compute_hash_on_elements(&[account_deployment_data_hash, calldata_hash]) }; - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ prefix, version, sender_address, @@ -146,16 +149,16 @@ impl ComputeTransactionHash for InvokeTransactionV3 { } impl ComputeTransactionHash for InvokeTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { match self { - InvokeTransaction::V0(tx) => tx.compute_hash::(chain_id, offset_version), - InvokeTransaction::V1(tx) => tx.compute_hash::(chain_id, offset_version), - InvokeTransaction::V3(tx) => tx.compute_hash::(chain_id, offset_version), + InvokeTransaction::V0(tx) => tx.compute_hash(chain_id, offset_version), + InvokeTransaction::V1(tx) => tx.compute_hash(chain_id, offset_version), + InvokeTransaction::V3(tx) => tx.compute_hash(chain_id, offset_version), } } } -fn compute_hash_declare_v0_or_v1( +fn compute_hash_declare_v0_or_v1( chain_id: Felt252Wrapper, offset_version: bool, tx: &DeclareTransactionV0V1, @@ -178,7 +181,7 @@ fn compute_hash_declare_v0_or_v1( FieldElement::from(version) }; - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, sender_address, @@ -192,7 +195,7 @@ fn compute_hash_declare_v0_or_v1( } impl ComputeTransactionHash for DeclareTransactionV2 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(DECLARE_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::TWO } else { FieldElement::TWO }; let sender_address = Felt252Wrapper::from(self.sender_address).into(); @@ -202,7 +205,7 @@ impl ComputeTransactionHash for DeclareTransactionV2 { let nonce = Felt252Wrapper::from(self.nonce).into(); let compiled_class_hash = Felt252Wrapper::from(self.compiled_class_hash).into(); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, sender_address, @@ -218,7 +221,7 @@ impl ComputeTransactionHash for DeclareTransactionV2 { } impl ComputeTransactionHash for DeclareTransactionV3 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(DECLARE_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::THREE } else { FieldElement::THREE }; @@ -238,7 +241,7 @@ impl ComputeTransactionHash for DeclareTransactionV3 { &self.account_deployment_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), ); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ prefix, version, sender_address, @@ -255,27 +258,27 @@ impl ComputeTransactionHash for DeclareTransactionV3 { } } impl ComputeTransactionHash for DeclareTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { match self { - DeclareTransaction::V0(tx) => compute_hash_declare_v0_or_v1::(chain_id, offset_version, tx, 0), - DeclareTransaction::V1(tx) => compute_hash_declare_v0_or_v1::(chain_id, offset_version, tx, 1), - DeclareTransaction::V2(tx) => tx.compute_hash::(chain_id, offset_version), - DeclareTransaction::V3(tx) => tx.compute_hash::(chain_id, offset_version), + DeclareTransaction::V0(tx) => compute_hash_declare_v0_or_v1(chain_id, offset_version, tx, 0), + DeclareTransaction::V1(tx) => compute_hash_declare_v0_or_v1(chain_id, offset_version, tx, 1), + DeclareTransaction::V2(tx) => tx.compute_hash(chain_id, offset_version), + DeclareTransaction::V3(tx) => tx.compute_hash(chain_id, offset_version), } } } impl ComputeTransactionHash for DeployAccountTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { match self { - DeployAccountTransaction::V1(tx) => tx.compute_hash::(chain_id, offset_version), - DeployAccountTransaction::V3(tx) => tx.compute_hash::(chain_id, offset_version), + DeployAccountTransaction::V1(tx) => tx.compute_hash(chain_id, offset_version), + DeployAccountTransaction::V3(tx) => tx.compute_hash(chain_id, offset_version), } } } impl ComputeTransactionHash for DeployAccountTransactionV1 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let constructor_calldata = convert_calldata(self.constructor_calldata.clone()); let contract_address = Felt252Wrapper::from( @@ -299,7 +302,7 @@ impl ComputeTransactionHash for DeployAccountTransactionV1 { let max_fee = FieldElement::from(self.max_fee.0); let nonce = Felt252Wrapper::from(self.nonce).into(); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, contract_address, @@ -314,7 +317,7 @@ impl ComputeTransactionHash for DeployAccountTransactionV1 { } impl ComputeTransactionHash for DeployAccountTransactionV3 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(DEPLOY_ACCOUNT_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::THREE } else { FieldElement::THREE }; @@ -342,7 +345,7 @@ impl ComputeTransactionHash for DeployAccountTransactionV3 { prepare_data_availability_modes(self.nonce_data_availability_mode, self.fee_data_availability_mode); let constructor_calldata_hash = compute_hash_on_elements(&constructor_calldata); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ prefix, version, contract_address, @@ -360,7 +363,7 @@ impl ComputeTransactionHash for DeployAccountTransactionV3 { } impl ComputeTransactionHash for L1HandlerTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { let prefix = FieldElement::from_byte_slice_be(L1_HANDLER_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET } else { FieldElement::ZERO }; let contract_address = Felt252Wrapper::from(self.contract_address).into(); @@ -368,7 +371,7 @@ impl ComputeTransactionHash for L1HandlerTransaction { let calldata_hash = compute_hash_on_elements(&convert_calldata(self.calldata.clone())); let nonce = Felt252Wrapper::from(self.nonce).into(); - Felt252Wrapper(H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, contract_address, diff --git a/crates/primitives/transactions/src/compute_hash_tests.rs b/crates/primitives/transactions/src/compute_hash_tests.rs index f9b3358121..a30f1d8b4a 100644 --- a/crates/primitives/transactions/src/compute_hash_tests.rs +++ b/crates/primitives/transactions/src/compute_hash_tests.rs @@ -1,7 +1,6 @@ use alloc::sync::Arc; use mp_felt::Felt252Wrapper; -use mp_hashers::pedersen::PedersenHasher; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_api::transaction::{ @@ -30,7 +29,7 @@ fn test_deploy_account_tx_hash() { class_hash: ClassHash(StarkFelt::THREE), }; - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } @@ -52,7 +51,7 @@ fn test_declare_v0_tx_hash() { sender_address: ContractAddress(PatriciaKey(StarkFelt::from(19911991_u128))), }); - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } @@ -74,7 +73,7 @@ fn test_declare_v1_tx_hash() { sender_address: ContractAddress(PatriciaKey(StarkFelt::from(19911991_u128))), }); - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } @@ -96,12 +95,12 @@ fn test_declare_v2_tx_hash() { compiled_class_hash: CompiledClassHash(StarkFelt::THREE), }; - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); let declare_v2_transaction = DeclareTransaction::V2(transaction); - let tx_hash = declare_v2_transaction.compute_hash::(chain_id, false); + let tx_hash = declare_v2_transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } @@ -122,7 +121,7 @@ fn test_invoke_tx_v1_hash() { calldata: Calldata(Arc::new(vec![StarkFelt::ONE, StarkFelt::TWO, StarkFelt::THREE])), }; - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } @@ -144,7 +143,7 @@ fn test_handle_l1_message_tx_hash() { version: Default::default(), }; - let tx_hash = transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } diff --git a/crates/primitives/transactions/src/from_broadcasted_transactions.rs b/crates/primitives/transactions/src/from_broadcasted_transactions.rs index 9e55267f85..7443752b46 100644 --- a/crates/primitives/transactions/src/from_broadcasted_transactions.rs +++ b/crates/primitives/transactions/src/from_broadcasted_transactions.rs @@ -1,6 +1,11 @@ use alloc::sync::Arc; -use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV0Inner, ContractClassV1}; +use blockifier::execution::contract_class::{ + ClassInfo, ContractClass, ContractClassV0, ContractClassV0Inner, ContractClassV1, +}; +use blockifier::execution::errors::ContractClassError; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::transactions::{DeclareTransaction, DeployAccountTransaction, InvokeTransaction}; use cairo_lang_starknet_classes::casm_contract_class::{ CasmContractClass, CasmContractEntryPoint, CasmContractEntryPoints, StarknetSierraCompilationError, }; @@ -13,23 +18,29 @@ use flate2::read::GzDecoder; use indexmap::IndexMap; use mp_felt::Felt252Wrapper; use num_bigint::{BigInt, BigUint, Sign}; -use starknet_api::core::EntryPointSelector; +use starknet_api::core::{calculate_contract_address, EntryPointSelector}; +use starknet_api::data_availability::DataAvailabilityMode; use starknet_api::deprecated_contract_class::{EntryPoint, EntryPointOffset, EntryPointType}; use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{ + AccountDeploymentData, Calldata, Fee, PaymasterData, Resource, ResourceBounds, ResourceBoundsMapping, Tip, + TransactionSignature, +}; +use starknet_api::StarknetApiError; use starknet_core::types::contract::legacy::{ LegacyContractClass, LegacyEntrypointOffset, RawLegacyEntryPoint, RawLegacyEntryPoints, }; use starknet_core::types::contract::{CompiledClass, CompiledClassEntrypoint, CompiledClassEntrypointList}; use starknet_core::types::{ BroadcastedDeclareTransaction, BroadcastedDeclareTransactionV1, BroadcastedDeclareTransactionV2, - BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, BroadcastedTransaction, - CompressedLegacyContractClass, EntryPointsByType, FlattenedSierraClass, LegacyContractEntryPoint, - LegacyEntryPointsByType, SierraEntryPoint, + BroadcastedDeclareTransactionV3, BroadcastedDeployAccountTransaction, BroadcastedInvokeTransaction, + BroadcastedTransaction, CompressedLegacyContractClass, EntryPointsByType, FlattenedSierraClass, + LegacyContractEntryPoint, LegacyEntryPointsByType, SierraEntryPoint, }; use starknet_crypto::FieldElement; use thiserror::Error; -use super::{DeclareTransaction, DeclareTransactionV1, DeclareTransactionV2, UserTransaction}; +use crate::compute_hash::ComputeTransactionHash; #[derive(Debug, Error)] pub enum BroadcastedTransactionConversionError { @@ -49,135 +60,200 @@ pub enum BroadcastedTransactionConversionError { SierraCompilationFailed, #[error("This transaction version is not supported")] UnsuportedTransactionVersion, + #[error("This transaction version is invalid for this tx")] + InvalidTransactionVersion, + #[error(transparent)] + StarknetApi(#[from] StarknetApiError), + #[error(transparent)] + ContractClass(#[from] ContractClassError), } -impl TryFrom for UserTransaction { - type Error = BroadcastedTransactionConversionError; - - fn try_from(tx: BroadcastedTransaction) -> Result { - match tx { - BroadcastedTransaction::Invoke(tx) => tx.try_into(), - BroadcastedTransaction::Declare(tx) => tx.try_into(), - BroadcastedTransaction::DeployAccount(tx) => tx.try_into(), - } +pub fn try_account_tx_from_broadcasted_tx( + tx: BroadcastedTransaction, + chain_id: Felt252Wrapper, +) -> Result { + match tx { + BroadcastedTransaction::Invoke(tx) => try_account_tx_from_broadcasted_invoke_tx(tx, chain_id), + BroadcastedTransaction::Declare(tx) => try_account_tx_from_broadcasted_declare_tx(tx, chain_id), + BroadcastedTransaction::DeployAccount(tx) => try_account_tx_from_broadcasted_deploy_tx(tx, chain_id), } } -fn cast_vec_of_field_elements(data: Vec) -> Vec { - // Non-copy but less dangerous than transmute - // https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives - - // Unsafe code but all invariants are checked: - - // 1. ptr must have been allocated using the global allocator -> data is allocated with the Global - // allocator. - // 2. T needs to have the same alignment as what ptr was allocated with -> Felt252Wrapper uses - // transparent representation of the inner type. - // 3. The allocated size in bytes needs to be the same as the pointer -> As FieldElement and - // Felt252Wrapper have the same size, and capacity is taken directly from the data Vector, we - // will have the same allocated byte size. - // 4. Length needs to be less than or equal to capacity -> data.len() is always less than or equal - // to data.capacity() - // 5. The first length values must be properly initialized values of type T -> ok since we use data - // which was correctly allocated - // 6. capacity needs to be the capacity that the pointer was allocated with -> data.as_mut_ptr() - // returns a pointer to memory having at least capacity initialized memory - // 7. The allocated size in bytes must be no larger than isize::MAX -> data.capacity() will never be - // bigger than isize::MAX (https://doc.rust-lang.org/std/vec/struct.Vec.html#panics-7) - let mut data = core::mem::ManuallyDrop::new(data); - unsafe { alloc::vec::Vec::from_raw_parts(data.as_mut_ptr() as *mut Felt252Wrapper, data.len(), data.capacity()) } -} - -impl TryFrom for UserTransaction { - type Error = BroadcastedTransactionConversionError; - - fn try_from(value: BroadcastedDeclareTransaction) -> Result { - let user_tx = match value { - BroadcastedDeclareTransaction::V1(BroadcastedDeclareTransactionV1 { - max_fee, - signature, - nonce, - contract_class, - sender_address, - is_query, - .. - }) => { - // Create a GzipDecoder to decompress the bytes - let mut gz = GzDecoder::new(&contract_class.program[..]); - - // Read the decompressed bytes into a Vec - let mut decompressed_bytes = Vec::new(); - std::io::Read::read_to_end(&mut gz, &mut decompressed_bytes) - .map_err(|_| BroadcastedTransactionConversionError::ProgramDecompressionFailed)?; - - let class_hash = { - let legacy_contract_class = LegacyContractClass { - program: serde_json::from_slice(decompressed_bytes.as_slice()) - .map_err(|_| BroadcastedTransactionConversionError::ProgramDeserializationFailed)?, - abi: match contract_class.abi.as_ref() { - Some(abi) => abi.iter().cloned().map(|entry| entry.into()).collect::>(), - None => vec![], - }, - entry_points_by_type: to_raw_legacy_entry_points(contract_class.entry_points_by_type.clone()), - }; - - legacy_contract_class - .class_hash() - .map_err(|_| BroadcastedTransactionConversionError::ClassHashComputationFailed)? +pub fn try_account_tx_from_broadcasted_declare_tx( + value: BroadcastedDeclareTransaction, + chain_id: Felt252Wrapper, +) -> Result { + let user_tx = match value { + BroadcastedDeclareTransaction::V1(BroadcastedDeclareTransactionV1 { + max_fee, + signature, + nonce, + contract_class: compresed_contract_class, + sender_address, + is_query, + }) => { + // Create a GzipDecoder to decompress the bytes + let mut gz = GzDecoder::new(&compresed_contract_class.program[..]); + + // Read the decompressed bytes into a Vec + let mut decompressed_bytes = Vec::new(); + std::io::Read::read_to_end(&mut gz, &mut decompressed_bytes) + .map_err(|_| BroadcastedTransactionConversionError::ProgramDecompressionFailed)?; + + let class_hash = { + let legacy_contract_class = LegacyContractClass { + program: serde_json::from_slice(decompressed_bytes.as_slice()) + .map_err(|_| BroadcastedTransactionConversionError::ProgramDeserializationFailed)?, + abi: match compresed_contract_class.abi.as_ref() { + Some(abi) => abi.iter().cloned().map(|entry| entry.into()).collect::>(), + None => vec![], + }, + entry_points_by_type: to_raw_legacy_entry_points( + compresed_contract_class.entry_points_by_type.clone(), + ), }; - let tx = DeclareTransaction::V1(DeclareTransactionV1 { - max_fee: max_fee.try_into().map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?, - signature: cast_vec_of_field_elements(signature), - nonce: nonce.into(), - class_hash: class_hash.into(), - sender_address: sender_address.into(), - offset_version: is_query, + legacy_contract_class + .class_hash() + .map_err(|_| BroadcastedTransactionConversionError::ClassHashComputationFailed)? + }; + let abi_length = compresed_contract_class.abi.as_ref().map(|abi| abi.len()).unwrap_or_default(); + let tx = + starknet_api::transaction::DeclareTransaction::V1(starknet_api::transaction::DeclareTransactionV0V1 { + max_fee: Fee(max_fee + .try_into() + .map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?), + signature: TransactionSignature( + signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(nonce).into(), + class_hash: Felt252Wrapper::from(class_hash).into(), + sender_address: Felt252Wrapper::from(sender_address).into(), }); - let contract_class = instantiate_blockifier_contract_class(contract_class, decompressed_bytes)?; + let contract_class = instantiate_blockifier_contract_class(compresed_contract_class, decompressed_bytes)?; + let tx_hash = tx.compute_hash(chain_id, is_query); - UserTransaction::Declare(tx, contract_class) + AccountTransaction::Declare({ + let class_info = ClassInfo::new(&contract_class, 0, abi_length)?; + if is_query { + DeclareTransaction::new_for_query(tx, tx_hash, class_info) + } else { + DeclareTransaction::new(tx, tx_hash, class_info) + } + .map_err(|_| BroadcastedTransactionConversionError::InvalidTransactionVersion)? + }) + } + BroadcastedDeclareTransaction::V2(BroadcastedDeclareTransactionV2 { + max_fee, + signature, + nonce, + contract_class: flattened_contract_class, + sender_address, + compiled_class_hash, + is_query, + }) => { + let sierra_contract_class = Felt252Wrapper::from(flattened_contract_class.class_hash()).into(); + let sierra_program_length = flattened_contract_class.sierra_program.len(); + let abi_length = flattened_contract_class.abi.len(); + + let casm_contract_class = flattened_sierra_to_casm_contract_class(flattened_contract_class) + .map_err(|_| BroadcastedTransactionConversionError::SierraCompilationFailed)?; + // ensure that the user has sign the correct class hash + if get_casm_contract_class_hash(&casm_contract_class) != compiled_class_hash { + return Err(BroadcastedTransactionConversionError::InvalidCompiledClassHash); } - BroadcastedDeclareTransaction::V2(BroadcastedDeclareTransactionV2 { - max_fee, - signature, - nonce, - contract_class, - sender_address, - compiled_class_hash, - is_query, - .. - }) => { - let tx = DeclareTransaction::V2(DeclareTransactionV2 { - max_fee: max_fee.try_into().map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?, - signature: cast_vec_of_field_elements(signature), - nonce: nonce.into(), - class_hash: contract_class.class_hash().into(), - sender_address: sender_address.into(), - compiled_class_hash: compiled_class_hash.into(), - offset_version: is_query, + let tx = + starknet_api::transaction::DeclareTransaction::V2(starknet_api::transaction::DeclareTransactionV2 { + max_fee: Fee(max_fee + .try_into() + .map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?), + signature: TransactionSignature( + signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(nonce).into(), + class_hash: sierra_contract_class, + sender_address: Felt252Wrapper::from(sender_address).into(), + compiled_class_hash: Felt252Wrapper::from(compiled_class_hash).into(), }); - let casm_contract_class = flattened_sierra_to_casm_contract_class(contract_class) - .map_err(|_| BroadcastedTransactionConversionError::SierraCompilationFailed)?; - - // ensure that the user has sign the correct class hash - if get_casm_cotract_class_hash(&casm_contract_class) != compiled_class_hash { - return Err(BroadcastedTransactionConversionError::InvalidCompiledClassHash); + let tx_hash = tx.compute_hash(chain_id, is_query); + let contract_class = ContractClass::V1( + ContractClassV1::try_from(casm_contract_class) + .map_err(|_| BroadcastedTransactionConversionError::CasmContractClassConversionFailed)?, + ); + + AccountTransaction::Declare({ + let class_info = ClassInfo::new(&contract_class, sierra_program_length, abi_length)?; + if is_query { + DeclareTransaction::new_for_query(tx, tx_hash, class_info) + } else { + DeclareTransaction::new(tx, tx_hash, class_info) } + .map_err(|_| BroadcastedTransactionConversionError::InvalidTransactionVersion)? + }) + } + BroadcastedDeclareTransaction::V3(BroadcastedDeclareTransactionV3 { + sender_address, + compiled_class_hash, + signature, + nonce, + contract_class: flattened_contract_class, + resource_bounds, + tip, + paymaster_data, + account_deployment_data, + nonce_data_availability_mode, + fee_data_availability_mode, + is_query, + }) => { + let sierra_contract_class = Felt252Wrapper::from(flattened_contract_class.class_hash()).into(); + let sierra_program_length = flattened_contract_class.sierra_program.len(); + let abi_length = flattened_contract_class.abi.len(); + + let casm_contract_class = flattened_sierra_to_casm_contract_class(flattened_contract_class) + .map_err(|_| BroadcastedTransactionConversionError::SierraCompilationFailed)?; + + let tx = + starknet_api::transaction::DeclareTransaction::V3(starknet_api::transaction::DeclareTransactionV3 { + resource_bounds: resource_bounds_mapping_conversion(resource_bounds), + tip: Tip(tip), + signature: TransactionSignature( + signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(nonce).into(), + class_hash: sierra_contract_class, + compiled_class_hash: Felt252Wrapper::from(compiled_class_hash).into(), + sender_address: Felt252Wrapper::from(sender_address).into(), + nonce_data_availability_mode: data_availability_mode_conversion(nonce_data_availability_mode), + fee_data_availability_mode: data_availability_mode_conversion(fee_data_availability_mode), + paymaster_data: PaymasterData( + paymaster_data.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + account_deployment_data: AccountDeploymentData( + account_deployment_data.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + }); - let contract_class = ContractClass::V1( - ContractClassV1::try_from(casm_contract_class) - .map_err(|_| BroadcastedTransactionConversionError::CasmContractClassConversionFailed)?, - ); - - UserTransaction::Declare(tx, contract_class) - } - }; + let tx_hash = tx.compute_hash(chain_id, is_query); + let contract_class = ContractClass::V1( + ContractClassV1::try_from(casm_contract_class) + .map_err(|_| BroadcastedTransactionConversionError::CasmContractClassConversionFailed)?, + ); + + AccountTransaction::Declare({ + let class_info = ClassInfo::new(&contract_class, sierra_program_length, abi_length)?; + if is_query { + DeclareTransaction::new_for_query(tx, tx_hash, class_info) + } else { + DeclareTransaction::new(tx, tx_hash, class_info) + } + .map_err(|_| BroadcastedTransactionConversionError::InvalidTransactionVersion)? + }) + } + }; - Ok(user_tx) - } + Ok(user_tx) } fn instantiate_blockifier_contract_class( @@ -294,7 +370,7 @@ fn entry_points_by_type_to_contract_entry_points(value: EntryPointsByType) -> Co } // Utils to convert Casm contract class to Compiled class -pub fn get_casm_cotract_class_hash(casm_contract_class: &CasmContractClass) -> FieldElement { +pub fn get_casm_contract_class_hash(casm_contract_class: &CasmContractClass) -> FieldElement { let compiled_class = casm_contract_class_to_compiled_class(casm_contract_class); compiled_class.class_hash().unwrap() } @@ -306,8 +382,10 @@ pub fn casm_contract_class_to_compiled_class(casm_contract_class: &CasmContractC compiler_version: casm_contract_class.compiler_version.clone(), bytecode: casm_contract_class.bytecode.iter().map(|x| biguint_to_field_element(&x.value)).collect(), entry_points_by_type: casm_entry_points_to_compiled_entry_points(&casm_contract_class.entry_points_by_type), - hints: vec![], // not needed to get class hash so ignoring this - pythonic_hints: None, // not needed to get class hash so ignoring this + // TODO: convert those too + hints: vec![], + pythonic_hints: None, + bytecode_segment_lengths: vec![], } } @@ -335,42 +413,168 @@ fn casm_entry_point_to_compiled_entry_point(value: &CasmContractEntryPoint) -> C } } -impl TryFrom for UserTransaction { - type Error = BroadcastedTransactionConversionError; - - fn try_from(value: BroadcastedInvokeTransaction) -> Result { - Ok(UserTransaction::Invoke(super::InvokeTransaction::V1(super::InvokeTransactionV1 { - max_fee: value.max_fee.try_into().map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?, - signature: cast_vec_of_field_elements(value.signature), - nonce: value.nonce.into(), - sender_address: value.sender_address.into(), - calldata: cast_vec_of_field_elements(value.calldata), - offset_version: value.is_query, - }))) - } +pub fn try_account_tx_from_broadcasted_invoke_tx( + broadcasted_tx: BroadcastedInvokeTransaction, + chain_id: Felt252Wrapper, +) -> Result { + Ok(match broadcasted_tx { + BroadcastedInvokeTransaction::V1(bc_tx) => { + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: Fee(bc_tx + .max_fee + .try_into() + .map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?), + signature: TransactionSignature( + bc_tx.signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(bc_tx.nonce).into(), + sender_address: Felt252Wrapper::from(bc_tx.sender_address).into(), + calldata: Calldata(Arc::new( + bc_tx.calldata.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + )), + }); + let tx_hash = tx.compute_hash(chain_id, bc_tx.is_query); + + AccountTransaction::Invoke(InvokeTransaction { tx, tx_hash, only_query: bc_tx.is_query }) + } + BroadcastedInvokeTransaction::V3(bc_tx) => { + let tx = starknet_api::transaction::InvokeTransaction::V3(starknet_api::transaction::InvokeTransactionV3 { + signature: TransactionSignature( + bc_tx.signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(bc_tx.nonce).into(), + sender_address: Felt252Wrapper::from(bc_tx.sender_address).into(), + calldata: Calldata(Arc::new( + bc_tx.calldata.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + )), + resource_bounds: resource_bounds_mapping_conversion(bc_tx.resource_bounds), + tip: Tip(bc_tx.tip), + nonce_data_availability_mode: data_availability_mode_conversion(bc_tx.nonce_data_availability_mode), + fee_data_availability_mode: data_availability_mode_conversion(bc_tx.fee_data_availability_mode), + paymaster_data: PaymasterData( + bc_tx.paymaster_data.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + account_deployment_data: AccountDeploymentData( + bc_tx.account_deployment_data.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + }); + let tx_hash = tx.compute_hash(chain_id, bc_tx.is_query); + + AccountTransaction::Invoke(InvokeTransaction { tx, tx_hash, only_query: bc_tx.is_query }) + } + }) } -impl TryFrom for UserTransaction { - type Error = BroadcastedTransactionConversionError; - - fn try_from(tx: BroadcastedDeployAccountTransaction) -> Result { - let tx = UserTransaction::DeployAccount(super::DeployAccountTransaction { - max_fee: tx.max_fee.try_into().map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?, - signature: cast_vec_of_field_elements(tx.signature), - nonce: tx.nonce.into(), - contract_address_salt: tx.contract_address_salt.into(), - constructor_calldata: cast_vec_of_field_elements(tx.constructor_calldata), - class_hash: tx.class_hash.into(), - offset_version: tx.is_query, - }); - - Ok(tx) +pub fn try_account_tx_from_broadcasted_deploy_tx( + broadcasted_tx: BroadcastedDeployAccountTransaction, + chain_id: Felt252Wrapper, +) -> Result { + Ok(match broadcasted_tx { + BroadcastedDeployAccountTransaction::V1(bc_tx) => { + let tx = starknet_api::transaction::DeployAccountTransaction::V1( + starknet_api::transaction::DeployAccountTransactionV1 { + max_fee: Fee(bc_tx + .max_fee + .try_into() + .map_err(|_| BroadcastedTransactionConversionError::MaxFeeTooBig)?), + signature: TransactionSignature( + bc_tx.signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(bc_tx.nonce).into(), + contract_address_salt: Felt252Wrapper::from(bc_tx.contract_address_salt).into(), + constructor_calldata: Calldata(Arc::new( + bc_tx.constructor_calldata.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + )), + class_hash: Felt252Wrapper::from(bc_tx.class_hash).into(), + }, + ); + let tx_hash = tx.compute_hash(chain_id, bc_tx.is_query); + let contract_address = calculate_contract_address( + tx.contract_address_salt(), + tx.class_hash(), + &tx.constructor_calldata(), + Default::default(), + )?; + AccountTransaction::DeployAccount(DeployAccountTransaction { + tx, + tx_hash, + contract_address, + only_query: bc_tx.is_query, + }) + } + BroadcastedDeployAccountTransaction::V3(bc_tx) => { + let tx = starknet_api::transaction::DeployAccountTransaction::V3( + starknet_api::transaction::DeployAccountTransactionV3 { + signature: TransactionSignature( + bc_tx.signature.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + nonce: Felt252Wrapper::from(bc_tx.nonce).into(), + contract_address_salt: Felt252Wrapper::from(bc_tx.contract_address_salt).into(), + constructor_calldata: Calldata(Arc::new( + bc_tx.constructor_calldata.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + )), + class_hash: Felt252Wrapper::from(bc_tx.class_hash).into(), + resource_bounds: resource_bounds_mapping_conversion(bc_tx.resource_bounds), + tip: Tip(bc_tx.tip), + nonce_data_availability_mode: data_availability_mode_conversion(bc_tx.nonce_data_availability_mode), + fee_data_availability_mode: data_availability_mode_conversion(bc_tx.fee_data_availability_mode), + paymaster_data: PaymasterData( + bc_tx.paymaster_data.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + ), + }, + ); + let tx_hash = tx.compute_hash(chain_id, bc_tx.is_query); + let contract_address = calculate_contract_address( + tx.contract_address_salt(), + tx.class_hash(), + &tx.constructor_calldata(), + Default::default(), + )?; + AccountTransaction::DeployAccount(DeployAccountTransaction { + tx, + tx_hash, + contract_address, + only_query: bc_tx.is_query, + }) + } + }) +} + +fn data_availability_mode_conversion( + da_mode: starknet_core::types::DataAvailabilityMode, +) -> starknet_api::data_availability::DataAvailabilityMode { + match da_mode { + starknet_core::types::DataAvailabilityMode::L1 => DataAvailabilityMode::L1, + starknet_core::types::DataAvailabilityMode::L2 => DataAvailabilityMode::L2, } } +fn resource_bounds_mapping_conversion( + resource_bounds: starknet_core::types::ResourceBoundsMapping, +) -> starknet_api::transaction::ResourceBoundsMapping { + ResourceBoundsMapping::try_from(vec![ + ( + Resource::L1Gas, + ResourceBounds { + max_amount: resource_bounds.l1_gas.max_amount, + max_price_per_unit: resource_bounds.l1_gas.max_price_per_unit, + }, + ), + ( + Resource::L2Gas, + ResourceBounds { + max_amount: resource_bounds.l2_gas.max_amount, + max_price_per_unit: resource_bounds.l2_gas.max_price_per_unit, + }, + ), + ]) + .unwrap() +} + #[cfg(test)] mod tests { use assert_matches::assert_matches; + use mp_hashers::pedersen::PedersenHasher; use starknet_core::types::contract::SierraClass; use starknet_core::types::FlattenedSierraClass; @@ -413,7 +617,7 @@ mod tests { }; let input: BroadcastedDeclareTransaction = BroadcastedDeclareTransaction::V1(txn); - assert!(UserTransaction::try_from(input).is_ok()); + assert!(try_account_tx_from_broadcasted_declare_tx::(input, Default::default()).is_ok()); } #[test] @@ -439,7 +643,7 @@ mod tests { let input: BroadcastedDeclareTransaction = BroadcastedDeclareTransaction::V1(txn); assert_matches!( - UserTransaction::try_from(input), + try_account_tx_from_broadcasted_declare_tx::(input, Default::default()), Err(BroadcastedTransactionConversionError::ProgramDecompressionFailed) ); } @@ -459,7 +663,7 @@ mod tests { }; let input: BroadcastedDeclareTransaction = BroadcastedDeclareTransaction::V2(txn); - assert!(UserTransaction::try_from(input).is_ok()); + assert!(try_account_tx_from_broadcasted_declare_tx::(input, Default::default()).is_ok()); } #[test] @@ -479,7 +683,7 @@ mod tests { let input: BroadcastedDeclareTransaction = BroadcastedDeclareTransaction::V2(txn); assert_matches!( - UserTransaction::try_from(input), + try_account_tx_from_broadcasted_declare_tx::(input, Default::default()), Err(BroadcastedTransactionConversionError::InvalidCompiledClassHash) ); } diff --git a/crates/primitives/transactions/src/lib.rs b/crates/primitives/transactions/src/lib.rs index 01b5b9ce5f..a8b79e23f3 100644 --- a/crates/primitives/transactions/src/lib.rs +++ b/crates/primitives/transactions/src/lib.rs @@ -5,20 +5,23 @@ pub extern crate alloc; pub mod compute_hash; // pub mod conversions; -// #[cfg(feature = "client")] -// pub mod from_broadcasted_transactions; +#[cfg(feature = "client")] +pub mod from_broadcasted_transactions; // pub mod getters; -// #[cfg(feature = "client")] -// pub mod to_starknet_core_transaction; +#[cfg(feature = "client")] +pub mod to_starknet_core_transaction; // #[cfg(feature = "client")] // pub mod utils; use alloc::vec::Vec; use blockifier::execution::contract_class::ContractClass; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::transaction_execution::Transaction; use blockifier::transaction::transaction_types::TransactionType; use derive_more::From; -use starknet_api::transaction::Fee; +use sp_core::H256; +use starknet_api::transaction::{Fee, TransactionHash}; use starknet_core::types::{MsgFromL1, TransactionExecutionStatus, TransactionFinalityStatus}; use starknet_ff::FieldElement; @@ -36,23 +39,76 @@ pub struct TransactionStatus { pub execution_status: TransactionExecutionStatus, } -// /// Wrapper type for transaction execution error. -// /// Different tx types. -// /// See `https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/` for more details. -// #[derive(Clone, Debug, PartialEq, Eq)] -// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -// #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, -// parity_scale_codec::Decode))] #[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] -// pub enum TxType { -// /// Regular invoke transaction. -// Invoke, -// /// Declare transaction. -// Declare, -// /// Deploy account transaction. -// DeployAccount, -// /// Message sent from ethereum. -// L1Handler, -// } +pub fn get_transaction_hash(tx: &Transaction) -> &TransactionHash { + match tx { + Transaction::AccountTransaction(tx) => get_account_transaction_hash(tx), + Transaction::L1HandlerTransaction(tx) => &tx.tx_hash, + } +} + +pub fn get_account_transaction_hash(tx: &AccountTransaction) -> &TransactionHash { + match tx { + AccountTransaction::Invoke(tx) => &tx.tx_hash, + AccountTransaction::Declare(tx) => &tx.tx_hash, + AccountTransaction::DeployAccount(tx) => &tx.tx_hash, + } +} + +/// Wrapper type for transaction execution error. +/// Different tx types. +/// See `https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/` for more details. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))] +#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] +pub enum TxType { + /// Regular invoke transaction. + Invoke, + /// Declare transaction. + Declare, + /// Deploy account transaction. + DeployAccount, + /// Message sent from ethereum. + L1Handler, +} + +// Adapted from pathfinder +pub fn compute_message_hash(tx: &starknet_api::transaction::L1HandlerTransaction) -> H256 { + use sha3::{Digest, Keccak256}; + + let Some((from_address, payload)) = tx.calldata.0.split_first() else { + // This would indicate a pretty severe error in the L1 transaction. + // But since we haven't encoded this during serialization, this could in + // theory mess us up here. + // + // We should incorporate this into the deserialization instead. Returning an + // error here is unergonomic and far too late. + return H256::zero(); + }; + + let mut hash = Keccak256::new(); + + // In the folowing lines we are abusing the fact that the internal representation of a StarkFelt is + // an big endian array of bytes [u8; 32] This is an ethereum address + // Should this internal representation change (and it will!!!) this would break + // TODO: add a test so it fails when the inner repr changes + hash.update(from_address.0); + hash.update(tx.contract_address.0.0.0); + hash.update(tx.nonce.0.0); + hash.update(tx.entry_point_selector.0.0); + + // Pad the u64 to 32 bytes to match a felt. + hash.update([0u8; 24]); + hash.update((payload.len() as u64).to_be_bytes()); + + for elem in payload { + hash.update(elem.0); + } + + let hash = <[u8; 32]>::from(hash.finalize()); + + hash.into() +} // impl From for TransactionType { // fn from(value: TxType) -> Self { @@ -65,24 +121,24 @@ pub struct TransactionStatus { // } // } -// impl From<&UserTransaction> for TxType { -// fn from(value: &UserTransaction) -> Self { -// match value { -// UserTransaction::Declare(_, _) => TxType::Declare, -// UserTransaction::DeployAccount(_) => TxType::DeployAccount, -// UserTransaction::Invoke(_) => TxType::Invoke, -// } -// } -// } +impl From<&AccountTransaction> for TxType { + fn from(value: &AccountTransaction) -> Self { + match value { + AccountTransaction::Declare(_) => TxType::Declare, + AccountTransaction::DeployAccount(_) => TxType::DeployAccount, + AccountTransaction::Invoke(_) => TxType::Invoke, + } + } +} -// impl From<&UserOrL1HandlerTransaction> for TxType { -// fn from(value: &UserOrL1HandlerTransaction) -> Self { -// match value { -// UserOrL1HandlerTransaction::User(tx) => tx.into(), -// UserOrL1HandlerTransaction::L1Handler(_, _) => TxType::L1Handler, -// } -// } -// } +impl From<&Transaction> for TxType { + fn from(value: &Transaction) -> Self { + match value { + Transaction::AccountTransaction(tx) => tx.into(), + Transaction::L1HandlerTransaction(_) => TxType::L1Handler, + } + } +} // #[derive(Clone, Debug, Eq, PartialEq, From)] // #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, diff --git a/crates/primitives/transactions/src/to_starknet_core_transaction.rs b/crates/primitives/transactions/src/to_starknet_core_transaction.rs index 651985c61a..191f9a5649 100644 --- a/crates/primitives/transactions/src/to_starknet_core_transaction.rs +++ b/crates/primitives/transactions/src/to_starknet_core_transaction.rs @@ -1,134 +1,214 @@ -use std::vec::Vec; - use mp_felt::Felt252Wrapper; use starknet_crypto::FieldElement; -fn cast_vec_of_felt_252_wrappers(data: Vec) -> Vec { - // Non-copy but less dangerous than transmute - // https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives - - // Unsafe code but all invariants are checked: - - // 1. ptr must have been allocated using the global allocator -> data is allocated with the Global - // allocator. - // 2. T needs to have the same alignment as what ptr was allocated with -> Felt252Wrapper uses - // transparent representation of the inner type. - // 3. The allocated size in bytes needs to be the same as the pointer -> As FieldElement and - // Felt252Wrapper have the same size, and capacity is taken directly from the data Vector, we - // will have the same allocated byte size. - // 4. Length needs to be less than or equal to capacity -> data.len() is always less than or equal - // to data.capacity() - // 5. The first length values must be properly initialized values of type T -> ok since we use data - // which was correctly allocated - // 6. capacity needs to be the capacity that the pointer was allocated with -> data.as_mut_ptr() - // returns a pointer to memory having at least capacity initialized memory - // 7. The allocated size in bytes must be no larger than isize::MAX -> data.capacity() will never be - // bigger than isize::MAX (https://doc.rust-lang.org/std/vec/struct.Vec.html#panics-7) - let mut data = core::mem::ManuallyDrop::new(data); - unsafe { alloc::vec::Vec::from_raw_parts(data.as_mut_ptr() as *mut FieldElement, data.len(), data.capacity()) } -} - pub fn to_starknet_core_tx( - tx: super::Transaction, - transaction_hash: FieldElement, + tx: blockifier::transaction::transaction_execution::Transaction, ) -> starknet_core::types::Transaction { match tx { - super::Transaction::Declare(tx, _contract_class) => { - let tx = match tx { - super::DeclareTransaction::V0(super::DeclareTransactionV0 { - max_fee, - signature, - nonce: _, - class_hash, - sender_address, - }) => starknet_core::types::DeclareTransaction::V0(starknet_core::types::DeclareTransactionV0 { - transaction_hash, - max_fee: max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(signature), - class_hash: class_hash.into(), - sender_address: sender_address.into(), - }), - super::DeclareTransaction::V1(super::DeclareTransactionV1 { - max_fee, - signature, - nonce, - class_hash, - sender_address, - .. - }) => starknet_core::types::DeclareTransaction::V1(starknet_core::types::DeclareTransactionV1 { - transaction_hash, - max_fee: max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(signature), - nonce: nonce.into(), - class_hash: class_hash.into(), - sender_address: sender_address.into(), - }), - super::DeclareTransaction::V2(super::DeclareTransactionV2 { - max_fee, - signature, - nonce, - class_hash, - sender_address, - compiled_class_hash, - .. - }) => starknet_core::types::DeclareTransaction::V2(starknet_core::types::DeclareTransactionV2 { - transaction_hash, - max_fee: max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(signature), - nonce: nonce.into(), - class_hash: class_hash.into(), - sender_address: sender_address.into(), - compiled_class_hash: compiled_class_hash.into(), - }), - }; - - starknet_core::types::Transaction::Declare(tx) + blockifier::transaction::transaction_execution::Transaction::AccountTransaction(acc_tx) => match acc_tx { + blockifier::transaction::account_transaction::AccountTransaction::Declare(dec_tx) => match dec_tx.tx { + starknet_api::transaction::DeclareTransaction::V0(tx) => starknet_core::types::Transaction::Declare( + starknet_core::types::DeclareTransaction::V0(starknet_core::types::DeclareTransactionV0 { + transaction_hash: Felt252Wrapper::from(dec_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + }), + ), + starknet_api::transaction::DeclareTransaction::V1(tx) => starknet_core::types::Transaction::Declare( + starknet_core::types::DeclareTransaction::V1(starknet_core::types::DeclareTransactionV1 { + transaction_hash: Felt252Wrapper::from(dec_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + }), + ), + starknet_api::transaction::DeclareTransaction::V2(tx) => starknet_core::types::Transaction::Declare( + starknet_core::types::DeclareTransaction::V2(starknet_core::types::DeclareTransactionV2 { + transaction_hash: Felt252Wrapper::from(dec_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + compiled_class_hash: Felt252Wrapper::from(tx.compiled_class_hash).into(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + }), + ), + starknet_api::transaction::DeclareTransaction::V3(tx) => starknet_core::types::Transaction::Declare( + starknet_core::types::DeclareTransaction::V3(starknet_core::types::DeclareTransactionV3 { + transaction_hash: Felt252Wrapper::from(dec_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + compiled_class_hash: Felt252Wrapper::from(tx.compiled_class_hash).into(), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + resource_bounds: resource_bounds_mapping_conversion(tx.resource_bounds), + tip: tx.tip.0, + paymaster_data: tx + .paymaster_data + .0 + .into_iter() + .map(|v| Felt252Wrapper::from(v).into()) + .collect(), + account_deployment_data: tx + .account_deployment_data + .0 + .into_iter() + .map(|v| Felt252Wrapper::from(v).into()) + .collect(), + nonce_data_availability_mode: data_availability_mode_conversion( + tx.nonce_data_availability_mode, + ), + fee_data_availability_mode: data_availability_mode_conversion(tx.fee_data_availability_mode), + }), + ), + }, + blockifier::transaction::account_transaction::AccountTransaction::DeployAccount(da_tx) => match da_tx.tx { + starknet_api::transaction::DeployAccountTransaction::V1(tx) => { + starknet_core::types::Transaction::DeployAccount( + starknet_core::types::DeployAccountTransaction::V1( + starknet_core::types::DeployAccountTransactionV1 { + transaction_hash: Felt252Wrapper::from(da_tx.tx_hash).into(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + contract_address_salt: Felt252Wrapper::from(tx.contract_address_salt).into(), + constructor_calldata: tx + .constructor_calldata + .0 + .iter() + .map(|&v| Felt252Wrapper::from(v).into()) + .collect(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + }, + ), + ) + } + starknet_api::transaction::DeployAccountTransaction::V3(tx) => { + starknet_core::types::Transaction::DeployAccount( + starknet_core::types::DeployAccountTransaction::V3( + starknet_core::types::DeployAccountTransactionV3 { + transaction_hash: Felt252Wrapper::from(da_tx.tx_hash).into(), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + contract_address_salt: Felt252Wrapper::from(tx.contract_address_salt).into(), + constructor_calldata: tx + .constructor_calldata + .0 + .iter() + .map(|&v| Felt252Wrapper::from(v).into()) + .collect(), + class_hash: Felt252Wrapper::from(tx.class_hash).into(), + resource_bounds: resource_bounds_mapping_conversion(tx.resource_bounds), + tip: tx.tip.0, + paymaster_data: tx + .paymaster_data + .0 + .into_iter() + .map(|v| Felt252Wrapper::from(v).into()) + .collect(), + nonce_data_availability_mode: data_availability_mode_conversion( + tx.nonce_data_availability_mode, + ), + fee_data_availability_mode: data_availability_mode_conversion( + tx.fee_data_availability_mode, + ), + }, + ), + ) + } + }, + blockifier::transaction::account_transaction::AccountTransaction::Invoke(inv_tx) => match inv_tx.tx { + starknet_api::transaction::InvokeTransaction::V0(tx) => starknet_core::types::Transaction::Invoke( + starknet_core::types::InvokeTransaction::V0(starknet_core::types::InvokeTransactionV0 { + transaction_hash: Felt252Wrapper::from(inv_tx.tx_hash).into(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + contract_address: Felt252Wrapper::from(tx.contract_address).into(), + entry_point_selector: Felt252Wrapper::from(tx.entry_point_selector).into(), + calldata: tx.calldata.0.iter().map(|&v| Felt252Wrapper::from(v).into()).collect(), + }), + ), + starknet_api::transaction::InvokeTransaction::V1(tx) => starknet_core::types::Transaction::Invoke( + starknet_core::types::InvokeTransaction::V1(starknet_core::types::InvokeTransactionV1 { + transaction_hash: Felt252Wrapper::from(inv_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + calldata: tx.calldata.0.iter().map(|&v| Felt252Wrapper::from(v).into()).collect(), + max_fee: FieldElement::from(tx.max_fee.0), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + }), + ), + starknet_api::transaction::InvokeTransaction::V3(tx) => starknet_core::types::Transaction::Invoke( + starknet_core::types::InvokeTransaction::V3(starknet_core::types::InvokeTransactionV3 { + transaction_hash: Felt252Wrapper::from(inv_tx.tx_hash).into(), + sender_address: Felt252Wrapper::from(tx.sender_address).into(), + calldata: tx.calldata.0.iter().map(|&v| Felt252Wrapper::from(v).into()).collect(), + signature: tx.signature.0.into_iter().map(|v| Felt252Wrapper::from(v).into()).collect(), + nonce: Felt252Wrapper::from(tx.nonce).into(), + resource_bounds: resource_bounds_mapping_conversion(tx.resource_bounds), + tip: tx.tip.0, + paymaster_data: tx + .paymaster_data + .0 + .into_iter() + .map(|v| Felt252Wrapper::from(v).into()) + .collect(), + account_deployment_data: tx + .account_deployment_data + .0 + .into_iter() + .map(|v| Felt252Wrapper::from(v).into()) + .collect(), + nonce_data_availability_mode: data_availability_mode_conversion( + tx.nonce_data_availability_mode, + ), + fee_data_availability_mode: data_availability_mode_conversion(tx.fee_data_availability_mode), + }), + ), + }, + }, + blockifier::transaction::transaction_execution::Transaction::L1HandlerTransaction(l1h_tx) => { + starknet_core::types::Transaction::L1Handler(starknet_core::types::L1HandlerTransaction { + transaction_hash: Felt252Wrapper::from(l1h_tx.tx_hash).into(), + version: FieldElement::ZERO, + // Safe to unwrap as long as there is less than u64::MAX messages sent from l1 to l1. + // We have some margin here. + nonce: u64::try_from(Felt252Wrapper::from(l1h_tx.tx.nonce)).unwrap(), + contract_address: Felt252Wrapper::from(l1h_tx.tx.contract_address).into(), + entry_point_selector: Felt252Wrapper::from(l1h_tx.tx.entry_point_selector).into(), + calldata: l1h_tx.tx.calldata.0.iter().map(|&v| Felt252Wrapper::from(v).into()).collect(), + }) } - super::Transaction::DeployAccount(tx) => { - let tx = starknet_core::types::DeployAccountTransaction { - transaction_hash, - max_fee: tx.max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(tx.signature), - nonce: tx.nonce.into(), - contract_address_salt: tx.contract_address_salt.into(), - constructor_calldata: cast_vec_of_felt_252_wrappers(tx.constructor_calldata), - class_hash: tx.class_hash.into(), - }; + } +} - starknet_core::types::Transaction::DeployAccount(tx) - } - super::Transaction::Invoke(tx) => { - let tx = match tx { - super::InvokeTransaction::V1(super::InvokeTransactionV1 { - max_fee, - signature, - nonce, - sender_address, - calldata, - .. - }) => starknet_core::types::InvokeTransaction::V1(starknet_core::types::InvokeTransactionV1 { - transaction_hash, - max_fee: max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(signature), - nonce: nonce.into(), - sender_address: sender_address.into(), - calldata: cast_vec_of_felt_252_wrappers(calldata), - }), - }; +fn data_availability_mode_conversion( + da_mode: starknet_api::data_availability::DataAvailabilityMode, +) -> starknet_core::types::DataAvailabilityMode { + match da_mode { + starknet_api::data_availability::DataAvailabilityMode::L1 => starknet_core::types::DataAvailabilityMode::L1, + starknet_api::data_availability::DataAvailabilityMode::L2 => starknet_core::types::DataAvailabilityMode::L2, + } +} - starknet_core::types::Transaction::Invoke(tx) - } - super::Transaction::L1Handler(tx) => { - let tx = starknet_core::types::L1HandlerTransaction { - transaction_hash, - version: 0, - nonce: tx.nonce, - contract_address: tx.contract_address.into(), - entry_point_selector: tx.entry_point_selector.into(), - calldata: cast_vec_of_felt_252_wrappers(tx.calldata), - }; +fn resource_bounds_mapping_conversion( + resource_bounds: starknet_api::transaction::ResourceBoundsMapping, +) -> starknet_core::types::ResourceBoundsMapping { + let l1_gas = resource_bounds.0.get(&starknet_api::transaction::Resource::L1Gas); + let l2_gas = resource_bounds.0.get(&starknet_api::transaction::Resource::L2Gas); - starknet_core::types::Transaction::L1Handler(tx) - } + starknet_core::types::ResourceBoundsMapping { + l1_gas: starknet_core::types::ResourceBounds { + max_amount: l1_gas.map(|v| v.max_amount).unwrap_or_default(), + max_price_per_unit: l1_gas.map(|v| v.max_price_per_unit).unwrap_or_default(), + }, + l2_gas: starknet_core::types::ResourceBounds { + max_amount: l2_gas.map(|v| v.max_amount).unwrap_or_default(), + max_price_per_unit: l2_gas.map(|v| v.max_price_per_unit).unwrap_or_default(), + }, } } diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index a17ed07f22..8ca54d82b7 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -250,11 +250,11 @@ impl_runtime_apis! { } fn contract_class_hash_by_address(address: ContractAddress) -> ClassHash { - Starknet::contract_class_hash_by_address(address) + ClassHash(Starknet::contract_class_hash_by_address(address)) } fn contract_class_by_class_hash(class_hash: ClassHash) -> Option { - Starknet::contract_class_by_class_hash(class_hash) + Starknet::contract_class_by_class_hash(class_hash.0) } fn chain_id() -> Felt252Wrapper { @@ -307,7 +307,7 @@ impl_runtime_apis! { }).collect::>() } - fn get_index_and_tx_for_tx_hash(extrinsics: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: TransactionHash) -> Option<(u32, Transaction)> { + fn get_index_and_tx_for_tx_hash(extrinsics: Vec<::Extrinsic>, tx_hash: TransactionHash) -> Option<(u32, Transaction)> { // Find our tx and it's index let (tx_index, tx) = extrinsics.into_iter().enumerate().find(|(_, xt)| { let computed_tx_hash = match &xt.function { diff --git a/starknet-rpc-test/add_declare_transaction.rs b/starknet-rpc-test/add_declare_transaction.rs index 44cf2134d1..92d4937e42 100644 --- a/starknet-rpc-test/add_declare_transaction.rs +++ b/starknet-rpc-test/add_declare_transaction.rs @@ -7,7 +7,7 @@ use rstest::rstest; use starknet_accounts::Account; use starknet_core::types::{BlockId, DeclareTransactionResult, StarknetError}; use starknet_ff::FieldElement; -use starknet_providers::{MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; +use starknet_providers::{Provider, ProviderError}; use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, OZ_CONTRACT_ADDRESS, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, read_erc20_balance, AccountActions, U256}; @@ -35,10 +35,7 @@ async fn fail_validation_step(madara: &ThreadSafeMadaraClient) -> Result<(), any assert_matches!( declare_tx_result, SendTransactionError::AccountError(starknet_accounts::AccountError::Provider(ProviderError::StarknetError( - StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ValidationFailure), - message: _ - } + StarknetError::ValidationFailure(_) ))) ); diff --git a/starknet-rpc-test/estimate_fee.rs b/starknet-rpc-test/estimate_fee.rs index 897246c12a..f4abc230c6 100644 --- a/starknet-rpc-test/estimate_fee.rs +++ b/starknet-rpc-test/estimate_fee.rs @@ -30,8 +30,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), }); assert_matches!( - rpc.estimate_fee(&vec![ok_invoke_transaction], BlockId::Hash(FieldElement::ZERO)).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.estimate_fee(&vec![ok_invoke_transaction], Default::default(), BlockId::Hash(FieldElement::ZERO)).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(())