diff --git a/Cargo.lock b/Cargo.lock index 7d6991d55a..831f5e936b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,6 +394,17 @@ dependencies = [ "ark-std 0.4.0", ] +[[package]] +name = "ark-secp256r1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "ark-secret-scalar" version = "0.0.2" @@ -816,7 +827,8 @@ dependencies = [ [[package]] name = "bincode" version = "2.0.0-rc.3" -source = "git+https://github.com/bincode-org/bincode.git?tag=v2.0.0-rc.3#aada4bb4cb457677a4b8e47572ae7ca8dd44927c" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" dependencies = [ "serde", ] @@ -978,41 +990,43 @@ dependencies = [ [[package]] name = "blockifier" -version = "0.1.0-rc2" -source = "git+https://github.com/keep-starknet-strange/blockifier?branch=no_std-support-7578442#dc3863a8cddc844b2a5ce7f368d13f603286a440" +version = "0.5.0-rc.3" +source = "git+https://github.com/bidzyyys/blockifier?branch=feature/scale-codec#a18daa717a894fbe64ba0fde42ba8861175245f7" dependencies = [ + "anyhow", + "ark-ec", "ark-ff 0.4.2", "ark-secp256k1", + "ark-secp256r1", "cached", "cairo-felt", "cairo-lang-casm", - "cairo-lang-casm-contract-class", + "cairo-lang-runner", + "cairo-lang-starknet-classes", "cairo-lang-utils", - "cairo-lang-vm-utils", "cairo-vm", "derive_more", - "hashbrown 0.14.3", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "itertools 0.10.5", "keccak", - "lazy_static", "log", "num-bigint", "num-integer", + "num-rational", "num-traits 0.2.17", + "once_cell", "parity-scale-codec", "phf", + "rstest 0.17.0", "scale-info", "serde", "serde_json", "sha3", - "sp-arithmetic 16.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", - "spin 0.9.8", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.5.2", "starknet_api", "strum 0.24.1", "strum_macros 0.24.3", - "thiserror-no-std", + "thiserror", ] [[package]] @@ -1150,56 +1164,68 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b195e4fbc4b6862bbd065b991a34750399c119797efff72492f28a5864de8700" dependencies = [ + "async-trait", + "cached_proc_macro", + "cached_proc_macro_types", + "futures", "hashbrown 0.13.2", "instant", "once_cell", "thiserror", + "tokio", +] + +[[package]] +name = "cached_proc_macro" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b48814962d2fd604c50d2b9433c2a41a0ab567779ee2c02f7fba6eca1221f082" +dependencies = [ + "cached_proc_macro_types", + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", ] +[[package]] +name = "cached_proc_macro_types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + [[package]] name = "cairo-felt" -version = "0.8.5" -source = "git+https://github.com/keep-starknet-strange/cairo-rs?branch=no_std-support-21eff70#f79edcaef28da6ff881942a0275374964831f21e" +version = "0.9.1" +source = "git+https://github.com/bidzyyys/cairo-vm?branch=feature/scale-codec#0641b5a018cd6fee7a01e627cab839f39bfaecb4" dependencies = [ "lazy_static", "num-bigint", "num-integer", "num-traits 0.2.17", "parity-scale-codec", + "scale-info", "serde", ] [[package]] name = "cairo-lang-casm" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-utils", - "hashbrown 0.14.3", "indoc", "num-bigint", "num-traits 0.2.17", "parity-scale-codec", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "cairo-lang-casm-contract-class" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" -dependencies = [ - "cairo-lang-casm", - "cairo-lang-utils", - "itertools 0.10.5", - "num-bigint", + "scale-info", "serde", ] [[package]] name = "cairo-lang-compiler" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "anyhow", "cairo-lang-defs", @@ -1207,15 +1233,12 @@ dependencies = [ "cairo-lang-filesystem", "cairo-lang-lowering", "cairo-lang-parser", - "cairo-lang-plugins", "cairo-lang-project", "cairo-lang-semantic", "cairo-lang-sierra", "cairo-lang-sierra-generator", "cairo-lang-syntax", "cairo-lang-utils", - "itertools 0.10.5", - "log", "salsa", "smol_str", "thiserror", @@ -1223,16 +1246,16 @@ dependencies = [ [[package]] name = "cairo-lang-debug" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-utils", ] [[package]] name = "cairo-lang-defs" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -1240,39 +1263,35 @@ dependencies = [ "cairo-lang-parser", "cairo-lang-syntax", "cairo-lang-utils", - "indexmap 2.0.0-pre", - "itertools 0.10.5", + "itertools 0.11.0", "salsa", "smol_str", ] [[package]] name = "cairo-lang-diagnostics" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", "cairo-lang-utils", - "itertools 0.10.5", - "salsa", + "itertools 0.11.0", ] [[package]] name = "cairo-lang-eq-solver" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-utils", "good_lp", - "indexmap 2.0.0-pre", - "itertools 0.10.5", ] [[package]] name = "cairo-lang-filesystem" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -1284,8 +1303,8 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1297,8 +1316,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-utils", "id-arena", - "indexmap 2.0.0-pre", - "itertools 0.10.5", + "itertools 0.11.0", "log", "num-bigint", "num-traits 0.2.17", @@ -1309,8 +1327,8 @@ dependencies = [ [[package]] name = "cairo-lang-parser" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -1318,8 +1336,7 @@ dependencies = [ "cairo-lang-syntax-codegen", "cairo-lang-utils", "colored", - "itertools 0.10.5", - "log", + "itertools 0.11.0", "num-bigint", "num-traits 0.2.17", "salsa", @@ -1329,28 +1346,26 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-parser", - "cairo-lang-semantic", "cairo-lang-syntax", "cairo-lang-utils", "indent", "indoc", - "itertools 0.10.5", - "num-bigint", + "itertools 0.11.0", "salsa", "smol_str", ] [[package]] name = "cairo-lang-proc-macros" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "quote", @@ -1359,33 +1374,63 @@ dependencies = [ [[package]] name = "cairo-lang-project" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", "serde", "smol_str", "thiserror", - "toml 0.7.8", + "toml 0.8.8", +] + +[[package]] +name = "cairo-lang-runner" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" +dependencies = [ + "ark-ff 0.4.2", + "ark-secp256k1", + "ark-secp256r1", + "ark-std 0.4.0", + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-generator", + "cairo-lang-sierra-to-casm", + "cairo-lang-sierra-type-size", + "cairo-lang-starknet", + "cairo-lang-utils", + "cairo-vm", + "itertools 0.11.0", + "keccak", + "num-bigint", + "num-integer", + "num-traits 0.2.17", + "smol_str", + "starknet-crypto 0.6.1", + "thiserror", ] [[package]] name = "cairo-lang-semantic" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-parser", + "cairo-lang-plugins", "cairo-lang-proc-macros", "cairo-lang-syntax", "cairo-lang-utils", "id-arena", - "itertools 0.10.5", - "log", + "indoc", + "itertools 0.11.0", "num-bigint", "num-traits 0.2.17", "once_cell", @@ -1395,14 +1440,16 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ + "anyhow", + "cairo-felt", "cairo-lang-utils", "const-fnv1a-hash", "convert_case 0.6.0", "derivative", - "itertools 0.10.5", + "itertools 0.11.0", "lalrpop", "lalrpop-util", "num-bigint", @@ -1410,6 +1457,7 @@ dependencies = [ "regex", "salsa", "serde", + "serde_json", "sha3", "smol_str", "thiserror", @@ -1417,34 +1465,36 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "itertools 0.10.5", + "itertools 0.11.0", + "num-traits 0.2.17", "thiserror", ] [[package]] name = "cairo-lang-sierra-gas" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "itertools 0.10.5", + "itertools 0.11.0", + "num-traits 0.2.17", "thiserror", ] [[package]] name = "cairo-lang-sierra-generator" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1452,15 +1502,11 @@ dependencies = [ "cairo-lang-filesystem", "cairo-lang-lowering", "cairo-lang-parser", - "cairo-lang-plugins", - "cairo-lang-proc-macros", "cairo-lang-semantic", "cairo-lang-sierra", "cairo-lang-syntax", "cairo-lang-utils", - "id-arena", - "indexmap 2.0.0-pre", - "itertools 0.10.5", + "itertools 0.11.0", "num-bigint", "once_cell", "salsa", @@ -1469,8 +1515,8 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "assert_matches", "cairo-felt", @@ -1481,8 +1527,7 @@ dependencies = [ "cairo-lang-sierra-type-size", "cairo-lang-utils", "indoc", - "itertools 0.10.5", - "log", + "itertools 0.11.0", "num-bigint", "num-traits 0.2.17", "thiserror", @@ -1490,8 +1535,8 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -1499,49 +1544,64 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "anyhow", "cairo-felt", - "cairo-lang-casm", - "cairo-lang-casm-contract-class", "cairo-lang-compiler", "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-filesystem", "cairo-lang-lowering", - "cairo-lang-parser", "cairo-lang-plugins", "cairo-lang-semantic", "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", + "cairo-lang-starknet-classes", "cairo-lang-syntax", "cairo-lang-utils", - "convert_case 0.6.0", - "genco", + "const_format", "indent", "indoc", - "itertools 0.10.5", - "log", + "itertools 0.11.0", + "once_cell", + "serde", + "serde_json", + "smol_str", + "thiserror", +] + +[[package]] +name = "cairo-lang-starknet-classes" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" +dependencies = [ + "cairo-felt", + "cairo-lang-casm", + "cairo-lang-sierra", + "cairo-lang-sierra-to-casm", + "cairo-lang-utils", + "convert_case 0.6.0", + "itertools 0.11.0", "num-bigint", "num-integer", "num-traits 0.2.17", "once_cell", + "parity-scale-codec", + "scale-info", "serde", "serde_json", "sha3", "smol_str", + "starknet-crypto 0.6.1", "thiserror", ] [[package]] name = "cairo-lang-syntax" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -1550,14 +1610,13 @@ dependencies = [ "num-traits 0.2.17", "salsa", "smol_str", - "thiserror", "unescaper", ] [[package]] name = "cairo-lang-syntax-codegen" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ "genco", "xshell", @@ -1565,49 +1624,24 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" +version = "2.6.0-rc.0" +source = "git+https://github.com/bidzyyys/cairo.git?branch=feature/scale-codec#8aceb3b55e7fb9dcfd1c00a37a62235fab4b4916" dependencies = [ - "cairo-felt", "hashbrown 0.14.3", - "indexmap 2.0.0-pre", - "itertools 0.10.5", + "indexmap 2.2.5", + "itertools 0.11.0", "num-bigint", - "num-integer", "num-traits 0.2.17", "parity-scale-codec", + "scale-info", + "schemars", "serde", ] -[[package]] -name = "cairo-lang-vm-utils" -version = "2.1.0" -source = "git+https://github.com/keep-starknet-strange/cairo.git?branch=no_std-support-8bbf530#f8b5fe438e0d201b7d1afb39c21d343ff95b5850" -dependencies = [ - "ark-ff 0.4.2", - "ark-std 0.4.0", - "cairo-felt", - "cairo-lang-casm", - "cairo-lang-utils", - "cairo-vm", - "hashbrown 0.14.3", - "num-bigint", - "num-integer", - "num-traits 0.2.17", -] - -[[package]] -name = "cairo-take_until_unbalanced" -version = "0.29.0" -source = "git+https://github.com/keep-starknet-strange/cairo-rs?branch=no_std-support-21eff70#f79edcaef28da6ff881942a0275374964831f21e" -dependencies = [ - "nom", -] - [[package]] name = "cairo-vm" -version = "0.8.5" -source = "git+https://github.com/keep-starknet-strange/cairo-rs?branch=no_std-support-21eff70#f79edcaef28da6ff881942a0275374964831f21e" +version = "0.9.1" +source = "git+https://github.com/bidzyyys/cairo-vm?branch=feature/scale-codec#0641b5a018cd6fee7a01e627cab839f39bfaecb4" dependencies = [ "anyhow", "ark-ff 0.4.2", @@ -1616,8 +1650,7 @@ dependencies = [ "bitvec", "cairo-felt", "cairo-lang-casm", - "cairo-lang-casm-contract-class", - "cairo-take_until_unbalanced", + "cairo-lang-starknet-classes", "generic-array 0.14.7", "hashbrown 0.14.3", "hex", @@ -1631,11 +1664,12 @@ dependencies = [ "num-traits 0.2.17", "parity-scale-codec", "rand 0.8.5", + "scale-info", "serde", "serde_json", "sha2 0.10.8", "sha3", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", + "starknet-crypto 0.6.1", "thiserror-no-std", ] @@ -2542,10 +2576,10 @@ dependencies = [ "lazy_static", "mc-data-availability", "reqwest", - "rstest", + "rstest 0.18.2", "serde", "serde_json", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", "starknet-providers", "starknet-rpc-test", "thiserror", @@ -4356,7 +4390,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -4613,7 +4647,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite 0.2.13", - "socket2 0.5.5", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -4817,21 +4851,13 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0-pre" -source = "git+https://github.com/bluss/indexmap?rev=ca5f848e10c31e80aeaad0720d14aa2f6dd6cfb1#ca5f848e10c31e80aeaad0720d14aa2f6dd6cfb1" -dependencies = [ - "hashbrown 0.13.2", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.1.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] @@ -6198,7 +6224,7 @@ dependencies = [ "sp-transaction-pool", "sp-version", "starknet-core", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", "starknet_api", "substrate-wasm-builder", ] @@ -6215,14 +6241,14 @@ dependencies = [ "flate2", "lazy_static", "reqwest", - "rstest", + "rstest 0.18.2", "serde", "serde_json", "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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-rpc-test", "starknet-signers", @@ -6291,7 +6317,7 @@ version = "0.7.0" dependencies = [ "blockifier", "futures", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "log", "mc-db", "mp-digest-log", @@ -6320,7 +6346,7 @@ dependencies = [ "clap 4.4.13", "ethers", "futures", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "jsonrpsee 0.20.3", "log", "mc-commitment-state-diff", @@ -6332,7 +6358,7 @@ dependencies = [ "mp-storage", "pallet-starknet-runtime-api", "reqwest", - "rstest", + "rstest 0.18.2", "sc-client-api", "serde", "serde_json", @@ -6401,11 +6427,13 @@ dependencies = [ name = "mc-l1-messages" version = "0.1.0" dependencies = [ + "blockifier", "ethers", "log", "mc-db", "mc-eth-client", "mp-felt", + "mp-hashers", "mp-transactions", "pallet-starknet-runtime-api", "rustc-hex", @@ -6427,6 +6455,7 @@ name = "mc-mapping-sync" version = "0.7.0" dependencies = [ "anyhow", + "blockifier", "futures", "futures-timer", "log", @@ -6451,10 +6480,11 @@ version = "0.7.0" dependencies = [ "anyhow", "blockifier", + "cairo-vm", "frame-support", "frame-system", "hex", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "itertools 0.12.0", "jsonrpsee 0.16.3", "log", @@ -6472,7 +6502,7 @@ dependencies = [ "pallet-starknet", "pallet-starknet-runtime-api", "pretty_assertions", - "rstest", + "rstest 0.18.2", "sc-client-api", "sc-network-sync", "sc-transaction-pool", @@ -6485,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", "starknet_api", "thiserror", "tokio", @@ -6499,14 +6529,14 @@ dependencies = [ "assert_matches", "blockifier", "cairo-lang-casm", - "cairo-lang-casm-contract-class", "cairo-lang-starknet", + "cairo-lang-starknet-classes", "cairo-lang-utils", "cairo-vm", "flate2", "frame-support", "hex", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "jsonrpsee 0.16.3", "mp-block", "mp-digest-log", @@ -6534,6 +6564,7 @@ name = "mc-settlement" version = "0.1.0" dependencies = [ "async-trait", + "blockifier", "clap 4.4.13", "ethers", "futures", @@ -6560,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", @@ -6773,7 +6804,6 @@ name = "mp-block" version = "0.7.0" dependencies = [ "blockifier", - "mp-fee", "mp-felt", "mp-hashers", "mp-transactions", @@ -6790,7 +6820,7 @@ name = "mp-chain-id" version = "0.7.0" dependencies = [ "mp-felt", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", ] [[package]] @@ -6808,17 +6838,8 @@ name = "mp-fee" version = "0.7.0" dependencies = [ "blockifier", - "hashbrown 0.14.3", - "mp-felt", - "mp-state", - "parity-scale-codec", - "phf", - "scale-info", - "serde", - "serde_with", - "sp-arithmetic 16.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", - "starknet-core", - "starknet_api", + "frame-support", + "sp-core 21.0.0 (git+https://github.com/massalabs/polkadot-sdk?branch=release-polkadot-v1.3.0-std)", ] [[package]] @@ -6833,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", "starknet_api", "thiserror-no-std", ] @@ -6850,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]] @@ -6862,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]] @@ -6883,7 +6904,7 @@ name = "mp-program-hash" version = "0.7.0" dependencies = [ "mp-felt", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.7", ] [[package]] @@ -6954,14 +6975,14 @@ version = "0.7.0" dependencies = [ "assert_matches", "blockifier", - "cairo-lang-casm-contract-class", "cairo-lang-starknet", + "cairo-lang-starknet-classes", "cairo-lang-utils", "cairo-vm", "derive_more", "flate2", + "indexmap 2.2.5", "log", - "mp-fee", "mp-felt", "mp-hashers", "mp-state", @@ -6970,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet_api", "thiserror", ] @@ -7375,6 +7398,7 @@ dependencies = [ "num-bigint", "num-integer", "num-traits 0.2.17", + "serde", ] [[package]] @@ -7665,15 +7689,15 @@ version = "0.7.0" dependencies = [ "assert_matches", "blockifier", - "cairo-lang-casm-contract-class", + "cairo-lang-starknet-classes", + "cairo-vm", "derive_more", "frame-benchmarking", "frame-support", "frame-system", - "hashbrown 0.14.3", "hex", "hexlit", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "lazy_static", "log", "mp-block", @@ -7708,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet_api", "test-case", ] @@ -8006,7 +8030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.1.0", + "indexmap 2.2.5", ] [[package]] @@ -8996,6 +9020,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rstest" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros 0.17.0", + "rustc_version 0.4.0", +] + [[package]] name = "rstest" version = "0.18.2" @@ -9004,10 +9040,24 @@ checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" dependencies = [ "futures", "futures-timer", - "rstest_macros", + "rstest_macros 0.18.2", "rustc_version 0.4.0", ] +[[package]] +name = "rstest_macros" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", + "unicode-ident", +] + [[package]] name = "rstest_macros" version = "0.18.2" @@ -10422,6 +10472,31 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + [[package]] name = "schnellru" version = "0.2.1" @@ -10643,6 +10718,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.111" @@ -12052,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", @@ -12065,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", @@ -12079,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", @@ -12090,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", ] [[package]] @@ -12108,8 +12194,9 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.6.1" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3f2175b0b3fc24ff2ec6dc07f5a720498994effca7e78b11a6e1c1bd02cad52" dependencies = [ "crypto-bigint", "hex", @@ -12119,16 +12206,17 @@ 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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto-codegen 0.3.2", + "starknet-curve 0.3.0", + "starknet-ff 0.3.6", "zeroize", ] [[package]] name = "starknet-crypto" version = "0.6.1" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22#a35ce22be52bf33b8e544d0df926031b0ec7d761" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c03f5ac70f9b067f48db7d2d70bdf18ee0f731e8192b6cfa679136becfcdb0" dependencies = [ "crypto-bigint", "hex", @@ -12138,46 +12226,76 @@ 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=a35ce22)", - "starknet-curve 0.4.0 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", + "starknet-crypto-codegen 0.3.2", + "starknet-curve 0.4.1", + "starknet-ff 0.3.6", + "zeroize", +] + +[[package]] +name = "starknet-crypto" +version = "0.6.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" +dependencies = [ + "crypto-bigint", + "hex", + "hmac 0.12.1", + "num-bigint", + "num-integer", + "num-traits 0.2.17", + "rfc6979", + "sha2 0.10.8", + "starknet-crypto-codegen 0.3.3", + "starknet-curve 0.4.2", + "starknet-ff 0.3.7", "zeroize", ] [[package]] name = "starknet-crypto-codegen" version = "0.3.2" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6527b845423542c8a16e060ea1bc43f67229848e7cd4c4d80be994a84220ce" dependencies = [ - "starknet-curve 0.4.0 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-curve 0.4.1", + "starknet-ff 0.3.6", "syn 2.0.48", ] [[package]] name = "starknet-crypto-codegen" -version = "0.3.2" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22#a35ce22be52bf33b8e544d0df926031b0ec7d761" +version = "0.3.3" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ - "starknet-curve 0.4.0 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", + "starknet-curve 0.4.2", + "starknet-ff 0.3.7", "syn 2.0.48", ] [[package]] name = "starknet-curve" -version = "0.4.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36#64ebc364c0c346e81b715c5b4a3b32ef37b055c8" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252610baff59e4c4332ce3569f7469c5d3f9b415a2240d698fb238b2b4fc0942" dependencies = [ - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-ff 0.3.6", ] [[package]] name = "starknet-curve" -version = "0.4.0" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22#a35ce22be52bf33b8e544d0df926031b0ec7d761" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c454fecadfb3fe56ee82c405439d663c8a037667cc9d8e4acb1fb17e15b1af" +dependencies = [ + "starknet-ff 0.3.6", +] + +[[package]] +name = "starknet-curve" +version = "0.4.2" +source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=2d59636911628260fa460179010bbd00e89de06e#2d59636911628260fa460179010bbd00e89de06e" dependencies = [ - "starknet-ff 0.3.5 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22)", + "starknet-ff 0.3.7", ] [[package]] @@ -12198,7 +12316,7 @@ dependencies = [ "mp-messages", "mp-snos-output", "reqwest", - "rstest", + "rstest 0.18.2", "sandbox", "serde", "serde_json", @@ -12206,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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-signers", "starknet_api", @@ -12219,32 +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.5" -source = "git+https://github.com/xJonathanLEI/starknet-rs.git?rev=a35ce22#a35ce22be52bf33b8e544d0df926031b0ec7d761" +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", @@ -12270,14 +12389,14 @@ dependencies = [ "async-trait", "flate2", "reqwest", - "rstest", + "rstest 0.18.2", "serde", "serde_json", "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 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.6.2", + "starknet-ff 0.3.7", "starknet-providers", "starknet-signers", "thiserror", @@ -12287,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", @@ -12296,27 +12415,29 @@ 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", ] [[package]] name = "starknet_api" -version = "0.4.1" -source = "git+https://github.com/keep-starknet-strange/starknet-api?branch=no_std-support-dc83f05#61980a2ea78f39b789f5dbd839ff4b3070c5f715" +version = "0.8.0" +source = "git+https://github.com/bidzyyys/starknet-api?branch=feature/scale-codec#902daafe539f040f12f80505f2a8c11011c68b83" dependencies = [ - "cairo-lang-casm-contract-class", + "cairo-lang-starknet-classes", "derive_more", - "hashbrown 0.14.3", "hex", - "indexmap 2.0.0-pre", + "indexmap 2.2.5", "once_cell", "parity-scale-codec", "primitive-types", "scale-info", "serde", "serde_json", - "starknet-crypto 0.6.1 (git+https://github.com/xJonathanLEI/starknet-rs.git?rev=64ebc36)", + "starknet-crypto 0.5.2", + "strum 0.24.1", + "strum_macros 0.24.3", + "thiserror", ] [[package]] @@ -13166,7 +13287,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -13179,7 +13300,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "toml_datetime", "winnow", ] @@ -13190,7 +13311,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -13487,7 +13608,7 @@ checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", "digest 0.10.7", - "rand 0.8.5", + "rand 0.7.3", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index c8b473f5fa..9b06844260 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,92 +85,92 @@ version = "0.7.0" [workspace.dependencies] # Substrate frame dependencies -frame-executive = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-executive = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-support = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-support = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-benchmarking = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-benchmarking = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-benchmarking-cli = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } -frame-system = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-benchmarking-cli = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +frame-system = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-system-benchmarking = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-system-benchmarking = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-system-rpc-runtime-api = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-system-rpc-runtime-api = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -frame-try-runtime = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +frame-try-runtime = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -substrate-frame-rpc-system = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } +substrate-frame-rpc-system = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } # Substrate primitives dependencies -sp-core = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-core = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-std = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-std = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-io = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-io = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-runtime = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-runtime = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-consensus-aura = { git = "http://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-consensus-aura = { git = "http://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-consensus = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-consensus = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-consensus-grandpa = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-consensus-grandpa = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-timestamp = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-timestamp = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-inherents = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-inherents = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-keyring = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } -sp-api = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-keyring = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +sp-api = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-blockchain = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } -sp-block-builder = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-blockchain = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +sp-block-builder = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-offchain = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-offchain = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-session = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-session = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-transaction-pool = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-transaction-pool = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-version = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-version = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-database = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } -sp-arithmetic = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-database = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +sp-arithmetic = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-storage = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-storage = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-state-machine = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-state-machine = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-statement-store = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-statement-store = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } -sp-trie = { version = "22.0.0", git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false, features = [ +sp-trie = { version = "22.0.0", git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", features = [ "std", ] } sp-tracing = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } @@ -184,7 +184,7 @@ sc-network-common = { git = "https://github.com/massalabs/polkadot-sdk", branch sc-network-sync = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } sc-consensus = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } # For integration tests in order to create blocks on demand -sc-consensus-manual-seal = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std", default-features = false } +sc-consensus-manual-seal = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } sc-consensus-grandpa = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } sc-rpc = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } sc-rpc-api = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } @@ -211,33 +211,33 @@ substrate-wasm-builder = { git = "https://github.com/massalabs/polkadot-sdk", br prometheus-endpoint = { package = "substrate-prometheus-endpoint", version = "0.10.0-dev", git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } # Substrate Frame pallet -pallet-aura = { default-features = true, git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } -pallet-grandpa = { default-features = true, git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } -pallet-timestamp = { default-features = true, git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +pallet-aura = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +pallet-grandpa = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } +pallet-timestamp = { git = "https://github.com/massalabs/polkadot-sdk", branch = "release-polkadot-v1.3.0-std" } # Madara pallets -pallet-starknet = { path = "crates/pallets/starknet", default-features = false, features = [ +pallet-starknet = { path = "crates/pallets/starknet", features = [ "std", ] } -pallet-starknet-runtime-api = { path = "crates/pallets/starknet/runtime_api", default-features = false, features = [ +pallet-starknet-runtime-api = { path = "crates/pallets/starknet/runtime_api", features = [ "std", ] } # Madara primtitives -mp-genesis-config = { path = "crates/primitives/genesis-config", default-features = false } -mp-digest-log = { path = "crates/primitives/digest-log", default-features = false } -mp-block = { path = "crates/primitives/block", default-features = false } -mp-fee = { path = "crates/primitives/fee", default-features = false } -mp-felt = { path = "crates/primitives/felt", default-features = false } -mp-hashers = { path = "crates/primitives/hashers", default-features = false } -mp-sequencer-address = { path = "crates/primitives/sequencer-address", default-features = false } -mp-snos-output = { path = "crates/primitives/snos-output", default-features = false } -mp-state = { path = "crates/primitives/state", default-features = false } -mp-storage = { path = "crates/primitives/storage", default-features = false } -mp-transactions = { path = "crates/primitives/transactions", default-features = false } -mp-chain-id = { path = "crates/primitives/chain-id", default-features = false } -mp-simulations = { path = "crates/primitives/simulations", default-features = false } -mp-program-hash = { path = "crates/primitives/program-hash", default-features = false } -mp-messages = { path = "crates/primitives/messages", default-features = false } +mp-genesis-config = { path = "crates/primitives/genesis-config" } +mp-digest-log = { path = "crates/primitives/digest-log" } +mp-block = { path = "crates/primitives/block" } +mp-fee = { path = "crates/primitives/fee" } +mp-felt = { path = "crates/primitives/felt" } +mp-hashers = { path = "crates/primitives/hashers" } +mp-sequencer-address = { path = "crates/primitives/sequencer-address" } +mp-snos-output = { path = "crates/primitives/snos-output" } +mp-state = { path = "crates/primitives/state" } +mp-storage = { path = "crates/primitives/storage" } +mp-transactions = { path = "crates/primitives/transactions" } +mp-chain-id = { path = "crates/primitives/chain-id" } +mp-simulations = { path = "crates/primitives/simulations" } +mp-program-hash = { path = "crates/primitives/program-hash" } +mp-messages = { path = "crates/primitives/messages" } # Madara client mc-genesis-data-provider = { path = "crates/client/genesis-data-provider" } @@ -260,46 +260,36 @@ madara-test-runner = { path = "madara-test-runner" } # Starknet dependencies # Cairo Virtual Machine -cairo-vm = { git = "https://github.com/keep-starknet-strange/cairo-rs", branch = "no_std-support-21eff70", default-features = false, features = [ +cairo-vm = { git = "https://github.com/bidzyyys/cairo-vm", branch = "feature/scale-codec", features = [ "std", "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", 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", 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" } +starknet-ff = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e", 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" } +starknet-accounts = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e" } +starknet-contract = { git = "https://github.com/xJonathanLEI/starknet-rs.git", rev = "2d59636911628260fa460179010bbd00e89de06e" } -blockifier = { git = "https://github.com/keep-starknet-strange/blockifier", branch = "no_std-support-7578442", default-features = false, features = [ - "std", - "parity-scale-codec", -] } -starknet_api = { git = "https://github.com/keep-starknet-strange/starknet-api", branch = "no_std-support-dc83f05", features = [ - "std", +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 = [ "testing", - "parity-scale-codec", -], default-features = false } + "parity-scale-codec" +] } # Cairo lang -cairo-lang-starknet = { git = "https://github.com/keep-starknet-strange/cairo.git", branch = "no_std-support-8bbf530" } -cairo-lang-casm-contract-class = { git = "https://github.com/keep-starknet-strange/cairo.git", branch = "no_std-support-8bbf530", default-features = false, features = [ - "std", -] } -cairo-lang-casm = { git = "https://github.com/keep-starknet-strange/cairo.git", branch = "no_std-support-8bbf530", default-features = false, features = [ - "std", -] } -cairo-lang-utils = { git = "https://github.com/keep-starknet-strange/cairo.git", branch = "no_std-support-8bbf530", default-features = false, features = [ - "std", -] } +cairo-lang-starknet = { git = "https://github.com/bidzyyys/cairo.git", branch = "feature/scale-codec" } +cairo-lang-starknet-classes = { git = "https://github.com/bidzyyys/cairo.git", branch = "feature/scale-codec" } +cairo-lang-casm = { git = "https://github.com/bidzyyys/cairo.git", branch = "feature/scale-codec" } +cairo-lang-utils = { git = "https://github.com/bidzyyys/cairo.git", branch = "feature/scale-codec" } # Ethers: using the same versions as in Anvil ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "f0e5b194f09c533feb10d1a686ddb9e5946ec107" } @@ -312,44 +302,42 @@ starknet-core-contract-client = { git = "https://github.com/keep-starknet-strang # Other third party dependencies anyhow = "1.0.80" flate2 = "1.0.28" -parity-scale-codec = { version = "3.2.2", default-features = false, features = [ +parity-scale-codec = { version = "3.2.2", features = [ "std", ] } -scale-info = { version = "2.10.0", default-features = false, features = [ +scale-info = { version = "2.10.0", features = [ "std", ] } -lazy_static = { version = "1.4.0", default-features = false } -log = { version = "0.4.20", default-features = false, features = ["std"] } -hex = { version = "0.4.3", default-features = false, features = ["std"] } -safe-mix = { version = "1.0", default-features = false, features = ["std"] } -jsonrpsee = { version = "0.16.3", default-features = false } -clap = { version = "4.4.8", default-features = false, features = ["std"] } -futures = { version = "0.3.29", default-features = false, features = ["std"] } -futures-timer = { version = "3.0.3", default-features = false } -sha3 = { version = "0.10.8", default-features = false, features = ["std"] } -reqwest = { version = "0.11.22", default-features = false } -serde = { version = "1.0.192", default-features = false, features = ["std"] } -serde_json = { version = "1.0.108", default-features = false, features = [ +lazy_static = { version = "1.4.0" } +log = { version = "0.4.20", features = ["std"] } +hex = { version = "0.4.3", features = ["std"] } +safe-mix = { version = "1.0", features = ["std"] } +jsonrpsee = { version = "0.16.3" } +clap = { version = "4.4.8", features = ["std"] } +futures = { version = "0.3.29", features = ["std"] } +futures-timer = { version = "3.0.3" } +sha3 = { version = "0.10.8", features = ["std"] } +reqwest = { version = "0.11.22" } +serde = { version = "1.0.192", features = ["std"] } +serde_json = { version = "1.0.108", features = [ "std", ] } -serde_with = { version = "2.3.3", default-features = false } -bitvec = { version = "1", default-features = false, features = ["std"] } +serde_with = { version = "2.3.3" } +bitvec = { version = "1", features = ["std"] } thiserror = "1.0.50" thiserror-no-std = "2.0.2" -derive_more = { version = "0.99.17", default-features = false } +derive_more = { version = "0.99.17" } rstest = "0.18.1" pretty_assertions = "1.4.0" -linked-hash-map = { version = "0.5.6", default-features = false, features = [ +linked-hash-map = { version = "0.5.6", features = [ "std", ] } parking_lot = "0.12.1" async-trait = "0.1.74" -indexmap = { git = "https://github.com/bluss/indexmap", rev = "ca5f848e10c31e80aeaad0720d14aa2f6dd6cfb1", default-features = false, features = [ - "std", -] } +indexmap = "2.2.5" num-traits = "0.2.17" num-bigint = "0.4.4" -phf = { version = "0.11", default-features = false, features = ["std"] } +phf = { version = "0.11", features = ["std"] } url = "2.4.1" hashbrown = "0.14.2" tokio = "1.36.0" diff --git a/configs/genesis-assets/genesis.json b/configs/genesis-assets/genesis.json index 38d96db6e7..f90c6715ce 100644 --- a/configs/genesis-assets/genesis.json +++ b/configs/genesis-assets/genesis.json @@ -295,5 +295,6 @@ "0x1" ] ], - "fee_token_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7" + "eth_fee_token_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "strk_fee_token_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc8" } diff --git a/configs/index.json b/configs/index.json index 4ec74b5bbc..9443548aa7 100644 --- a/configs/index.json +++ b/configs/index.json @@ -27,7 +27,7 @@ }, { "name": "genesis.json", - "sha3_256": "954b26a63a70ba92cbc79028fbdaf4f70105ba32ff71b60a24ecce775b4dd90c" + "sha3_256": "4e7792f7155d504e87fc57b6bed255543cdf355400feaa81890f3842cf6e3839" }, { "name": "NoValidateAccount.casm.json", diff --git a/crates/client/commitment-state-diff/src/lib.rs b/crates/client/commitment-state-diff/src/lib.rs index 8bb61c2403..f94ebff11a 100644 --- a/crates/client/commitment-state-diff/src/lib.rs +++ b/crates/client/commitment-state-diff/src/lib.rs @@ -14,8 +14,8 @@ use sc_client_api::{StorageEventStream, StorageNotification}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_runtime::traits::{Block as BlockT, Header}; -use starknet_api::api_core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::block::BlockHash; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::{StorageKey as StarknetStorageKey, ThinStateDiff}; use thiserror::Error; diff --git a/crates/client/data-availability/src/utils.rs b/crates/client/data-availability/src/utils.rs index 48f7c925e0..034e0e34b0 100644 --- a/crates/client/data-availability/src/utils.rs +++ b/crates/client/data-availability/src/utils.rs @@ -1,6 +1,6 @@ use ethers::types::U256; use mc_commitment_state_diff::BlockDAData; -use starknet_api::api_core::{Nonce, PatriciaKey}; +use starknet_api::core::{Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use url::{ParseError, Url}; diff --git a/crates/client/db/Cargo.toml b/crates/client/db/Cargo.toml index 8afe806242..12517d6211 100644 --- a/crates/client/db/Cargo.toml +++ b/crates/client/db/Cargo.toml @@ -27,9 +27,7 @@ sc-client-db = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-database = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } -starknet_api = { workspace = true, default-features = true, features = [ - "parity-scale-codec", -] } +starknet_api = { workspace = true, default-features = true } thiserror = { workspace = true } uuid = "1.7.0" 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/db/src/sierra_classes_db.rs b/crates/client/db/src/sierra_classes_db.rs index b88138085d..23e6da792f 100644 --- a/crates/client/db/src/sierra_classes_db.rs +++ b/crates/client/db/src/sierra_classes_db.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use parity_scale_codec::{Decode, Encode}; use sp_database::Database; -use starknet_api::api_core::ClassHash; +use starknet_api::core::ClassHash; use starknet_api::state::ContractClass; use crate::{DbError, DbHash}; diff --git a/crates/client/l1-messages/Cargo.toml b/crates/client/l1-messages/Cargo.toml index 7512200d3b..867f4bf52a 100644 --- a/crates/client/l1-messages/Cargo.toml +++ b/crates/client/l1-messages/Cargo.toml @@ -21,6 +21,7 @@ pallet-starknet-runtime-api = { workspace = true, default-features = true } # Starknet dependencies starknet_api = { workspace = true, default-features = true } +blockifier = { workspace = true, default-features = true } # Starknet mc-db = { workspace = true, default-features = true } @@ -29,6 +30,7 @@ mc-eth-client = { workspace = true } # Madara Primitives mp-felt = { workspace = true, default-features = true } mp-transactions = { workspace = true, default-features = true } +mp-hashers = { workspace = true, default-features = true } # Substrate Primitives sp-api = { workspace = true, default-features = true } diff --git a/crates/client/l1-messages/src/contract.rs b/crates/client/l1-messages/src/contract.rs index add732b0ee..e999e567b8 100644 --- a/crates/client/l1-messages/src/contract.rs +++ b/crates/client/l1-messages/src/contract.rs @@ -1,5 +1,8 @@ +use std::sync::Arc; + use mp_felt::{Felt252Wrapper, Felt252WrapperError}; -use mp_transactions::HandleL1MessageTransaction; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{Calldata, L1HandlerTransaction, TransactionVersion}; use starknet_core_contract_client::interfaces::LogMessageToL2Filter; #[derive(thiserror::Error, Debug, PartialEq)] @@ -19,35 +22,46 @@ pub enum L1EventToTransactionError { pub fn parse_handle_l1_message_transaction( event: LogMessageToL2Filter, -) -> Result { +) -> Result { // L1 from address. let from_address = Felt252Wrapper::try_from(sp_core::U256::from_big_endian(event.from_address.as_bytes())) - .map_err(L1EventToTransactionError::InvalidFromAddress)?; + .map_err(L1EventToTransactionError::InvalidFromAddress)? + .into(); // L2 contract to call. let contract_address = Felt252Wrapper::try_from(sp_core::U256(event.to_address.0)) - .map_err(L1EventToTransactionError::InvalidContractAddress)?; + .map_err(L1EventToTransactionError::InvalidContractAddress)? + .into(); // Function of the contract to call. let entry_point_selector = Felt252Wrapper::try_from(sp_core::U256(event.selector.0)) - .map_err(L1EventToTransactionError::InvalidEntryPointSelector)?; + .map_err(L1EventToTransactionError::InvalidEntryPointSelector)? + .into(); // L1 message nonce. - let nonce: u64 = Felt252Wrapper::try_from(sp_core::U256(event.nonce.0)) - .map_err(L1EventToTransactionError::InvalidNonce)? - .try_into() - .map_err(L1EventToTransactionError::InvalidNonce)?; + let nonce = + Felt252Wrapper::try_from(sp_core::U256(event.nonce.0)).map_err(L1EventToTransactionError::InvalidNonce)?.into(); - let event_payload: Vec = event + let event_payload: Vec<_> = event .payload .iter() - .map(|param| Felt252Wrapper::try_from(sp_core::U256(param.0))) - .collect::, Felt252WrapperError>>() + .map(|param| Felt252Wrapper::try_from(sp_core::U256(param.0)).map(StarkFelt::from)) + .collect::, Felt252WrapperError>>() .map_err(L1EventToTransactionError::InvalidCalldata)?; - let mut calldata: Vec = Vec::with_capacity(event.payload.len() + 1); - calldata.push(from_address); - event_payload.iter().collect_into(&mut calldata); + let calldata = { + let mut calldata: Vec<_> = Vec::with_capacity(event.payload.len() + 1); + calldata.push(from_address); + event_payload.iter().collect_into(&mut calldata); + + Calldata(Arc::new(calldata)) + }; - Ok(HandleL1MessageTransaction { nonce, contract_address, entry_point_selector, calldata }) + Ok(L1HandlerTransaction { + nonce, + contract_address, + entry_point_selector, + calldata, + version: TransactionVersion(StarkFelt::ZERO), + }) } diff --git a/crates/client/l1-messages/src/worker.rs b/crates/client/l1-messages/src/worker.rs index 08743028a6..d5164175e6 100644 --- a/crates/client/l1-messages/src/worker.rs +++ b/crates/client/l1-messages/src/worker.rs @@ -3,14 +3,12 @@ use std::sync::Arc; use ethers::providers::{Http, Provider, StreamExt}; use ethers::types::U256; pub use mc_eth_client::config::EthereumClientConfig; -use mp_transactions::HandleL1MessageTransaction; +use mp_transactions::compute_hash::ComputeTransactionHash; use pallet_starknet_runtime_api::{ConvertTransactionRuntimeApi, StarknetRuntimeApi}; use sc_client_api::HeaderBackend; use sc_transaction_pool_api::{TransactionPool, TransactionSource}; use sp_api::ProvideRuntimeApi; use sp_runtime::traits::Block as BlockT; -use starknet_api::api_core::Nonce; -use starknet_api::hash::StarkFelt; use starknet_api::transaction::Fee; use starknet_core_contract_client::interfaces::{LogMessageToL2Filter, StarknetMessagingEvents}; @@ -74,7 +72,7 @@ pub async fn run_worker( meta.log_index ); - match process_l1_message( + match process_l1_message::<_, _, _, _>( event, &client, &pool, @@ -127,19 +125,19 @@ where { // Check against panic // https://docs.rs/ethers/latest/ethers/types/struct.U256.html#method.as_u128 - let fee: Fee = if event.fee > U256::from_big_endian(&(u128::MAX.to_be_bytes())) { + let paid_fee_on_l1: Fee = if event.fee > U256::from_big_endian(&(u128::MAX.to_be_bytes())) { return Err(L1MessagesWorkerError::ToFeeError); } else { Fee(event.fee.as_u128()) }; - let transaction: HandleL1MessageTransaction = parse_handle_l1_message_transaction(event)?; + let tx = parse_handle_l1_message_transaction(event)?; let best_block_hash = client.info().best_hash; - match client.runtime_api().l1_nonce_unused(best_block_hash, Nonce(StarkFelt::from(transaction.nonce))) { + match client.runtime_api().l1_nonce_unused(best_block_hash, tx.nonce) { Ok(true) => Ok(()), Ok(false) => { - log::debug!("⟠ Event already processed: {:?}", transaction); + log::debug!("⟠ Event already processed: {:?}", tx); return Ok(None); } Err(e) => { @@ -148,7 +146,13 @@ where } }?; - let extrinsic = client.runtime_api().convert_l1_transaction(best_block_hash, transaction, fee).map_err(|e| { + 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 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| { log::error!("⟠ Failed to convert L1 Transaction via Runtime Api: {:?}", e); L1MessagesWorkerError::ConvertTransactionRuntimeApiError(e) })?; diff --git a/crates/client/mapping-sync/Cargo.toml b/crates/client/mapping-sync/Cargo.toml index 84dadb63a8..6829eac5a7 100644 --- a/crates/client/mapping-sync/Cargo.toml +++ b/crates/client/mapping-sync/Cargo.toml @@ -30,3 +30,4 @@ sp-api = { workspace = true } sp-blockchain = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +blockifier = { workspace = true } diff --git a/crates/client/mapping-sync/src/sync_blocks.rs b/crates/client/mapping-sync/src/sync_blocks.rs index 02d1fd8e8d..b21bd859b2 100644 --- a/crates/client/mapping-sync/src/sync_blocks.rs +++ b/crates/client/mapping-sync/src/sync_blocks.rs @@ -1,7 +1,10 @@ +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; @@ -36,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, @@ -45,7 +46,8 @@ where starknet_transaction_hashes: digest_starknet_block .transactions() .iter() - .map(|tx| tx.compute_hash::(chain_id, false).into()) + .map(get_transaction_hash) + .cloned() .collect(), }; diff --git a/crates/client/rpc-core/Cargo.toml b/crates/client/rpc-core/Cargo.toml index af6fc4068e..0615af3f52 100644 --- a/crates/client/rpc-core/Cargo.toml +++ b/crates/client/rpc-core/Cargo.toml @@ -19,7 +19,7 @@ targets = ["x86_64-unknown-linux-gnu"] anyhow = { workspace = true } blockifier = { workspace = true, default-features = true } cairo-lang-casm = { workspace = true } -cairo-lang-casm-contract-class = { workspace = true } +cairo-lang-starknet-classes = { workspace = true } cairo-lang-starknet = { workspace = true } cairo-lang-utils = { workspace = true } cairo-vm = { workspace = true, default-features = true } diff --git a/crates/client/rpc-core/src/utils.rs b/crates/client/rpc-core/src/utils.rs index 2c22d1dcad..df3291c9ec 100644 --- a/crates/client/rpc-core/src/utils.rs +++ b/crates/client/rpc-core/src/utils.rs @@ -1,15 +1,15 @@ -use std::collections::HashMap; use std::io::Write; use std::sync::Arc; use anyhow::{anyhow, Result}; use blockifier::execution::contract_class::ContractClass as BlockifierContractClass; use blockifier::state::cached_state::CommitmentStateDiff; -use cairo_lang_casm_contract_class::{CasmContractClass, CasmContractEntryPoint, CasmContractEntryPoints}; -use cairo_lang_starknet::contract_class::{ +use cairo_lang_starknet_classes::casm_contract_class::{ + CasmContractClass, CasmContractEntryPoint, CasmContractEntryPoints, StarknetSierraCompilationError, +}; +use cairo_lang_starknet_classes::contract_class::{ ContractClass as SierraContractClass, ContractEntryPoint, ContractEntryPoints, }; -use cairo_lang_starknet::contract_class_into_casm_contract_class::StarknetSierraCompilationError; use cairo_lang_utils::bigint::BigUintAsHex; use indexmap::IndexMap; use mp_block::Block as StarknetBlock; @@ -32,7 +32,7 @@ pub fn blockifier_to_rpc_contract_class_types(contract_class: BlockifierContract match contract_class { BlockifierContractClass::V0(contract_class) => { let entry_points_by_type = to_legacy_entry_points_by_type(&contract_class.entry_points_by_type)?; - let compressed_program = compress(&contract_class.program.to_bytes())?; + let compressed_program = compress(&contract_class.program.serialize()?)?; Ok(ContractClass::Legacy(CompressedLegacyContractClass { program: compressed_program, entry_points_by_type, @@ -57,9 +57,12 @@ pub fn blockifier_to_rpc_state_diff_types(commitment_state_diff: CommitmentState .map(|(address, storage_map)| { let storage_entries = storage_map .into_iter() - .map(|(key, value)| StorageEntry { key: key.0.0.into(), value: value.into() }) + .map(|(key, value)| StorageEntry { + key: Felt252Wrapper::from(key.0.0).into(), + value: Felt252Wrapper::from(value).into(), + }) .collect(); - ContractStorageDiffItem { address: address.0.0.into(), storage_entries } + ContractStorageDiffItem { address: Felt252Wrapper::from(address.0.0).into(), storage_entries } }) .collect(); @@ -67,8 +70,8 @@ pub fn blockifier_to_rpc_state_diff_types(commitment_state_diff: CommitmentState .class_hash_to_compiled_class_hash .into_iter() .map(|(class_hash, compiled_class_hash)| DeclaredClassItem { - class_hash: class_hash.0.into(), - compiled_class_hash: compiled_class_hash.0.into(), + class_hash: Felt252Wrapper::from(class_hash.0).into(), + compiled_class_hash: Felt252Wrapper::from(compiled_class_hash.0).into(), }) .collect(); @@ -76,15 +79,18 @@ pub fn blockifier_to_rpc_state_diff_types(commitment_state_diff: CommitmentState .address_to_class_hash .into_iter() .map(|(address, class_hash)| DeployedContractItem { - address: address.0.0.into(), - class_hash: class_hash.0.into(), + address: Felt252Wrapper::from(address.0.0).into(), + class_hash: Felt252Wrapper::from(class_hash.0).into(), }) .collect(); let nonces = commitment_state_diff .address_to_nonce .into_iter() - .map(|(address, nonce)| NonceUpdate { contract_address: address.0.0.into(), nonce: nonce.0.into() }) + .map(|(address, nonce)| NonceUpdate { + contract_address: Felt252Wrapper::from(address.0.0).into(), + nonce: Felt252Wrapper::from(nonce.0).into(), + }) .collect(); Ok(StateDiff { @@ -102,36 +108,56 @@ pub fn to_rpc_state_diff(thin_state_diff: ThinStateDiff) -> StateDiff { let nonces = thin_state_diff .nonces .iter() - .map(|x| NonceUpdate { contract_address: x.0.0.0.into(), nonce: x.1.0.into() }) + .map(|x| NonceUpdate { + contract_address: Felt252Wrapper::from(x.0.0.0).into(), + nonce: Felt252Wrapper::from(x.1.0).into(), + }) .collect(); let storage_diffs = thin_state_diff .storage_diffs .iter() .map(|x| ContractStorageDiffItem { - address: x.0.0.0.into(), - storage_entries: x.1.iter().map(|y| StorageEntry { key: y.0.0.0.into(), value: (*y.1).into() }).collect(), + address: Felt252Wrapper::from(x.0.0.0).into(), + storage_entries: x + .1 + .iter() + .map(|y| StorageEntry { + key: Felt252Wrapper::from(y.0.0.0).into(), + value: Felt252Wrapper::from(*y.1).into(), + }) + .collect(), }) .collect(); - let deprecated_declared_classes = thin_state_diff.deprecated_declared_classes.iter().map(|x| x.0.into()).collect(); + let deprecated_declared_classes = + thin_state_diff.deprecated_declared_classes.iter().map(|x| Felt252Wrapper::from(x.0).into()).collect(); let declared_classes = thin_state_diff .declared_classes .iter() - .map(|x| DeclaredClassItem { class_hash: x.0.0.into(), compiled_class_hash: x.1.0.into() }) + .map(|x| DeclaredClassItem { + class_hash: Felt252Wrapper::from(x.0.0).into(), + compiled_class_hash: Felt252Wrapper::from(x.1.0).into(), + }) .collect(); let deployed_contracts = thin_state_diff .deployed_contracts .iter() - .map(|x| DeployedContractItem { address: x.0.0.0.into(), class_hash: x.1.0.into() }) + .map(|x| DeployedContractItem { + address: Felt252Wrapper::from(x.0.0.0).into(), + class_hash: Felt252Wrapper::from(x.1.0).into(), + }) .collect(); let replaced_classes = thin_state_diff .replaced_classes .iter() - .map(|x| ReplacedClassItem { contract_address: x.0.0.0.into(), class_hash: x.1.0.into() }) + .map(|x| ReplacedClassItem { + contract_address: Felt252Wrapper::from(x.0.0.0).into(), + class_hash: Felt252Wrapper::from(x.1.0).into(), + }) .collect(); StateDiff { @@ -158,10 +184,10 @@ pub(crate) fn compress(data: &[u8]) -> Result> { /// Returns a [Result] (starknet-rs type) from a [HashMap>] fn to_legacy_entry_points_by_type( - entries: &HashMap>, + entries: &IndexMap>, ) -> Result { fn collect_entry_points( - entries: &HashMap>, + entries: &IndexMap>, entry_point_type: EntryPointType, ) -> Result> { Ok(entries @@ -214,36 +240,36 @@ pub fn flattened_sierra_to_casm_contract_class( ), abi: None, // we can convert the ABI but for now, to convert to Casm, the ABI isn't needed }; - let casm_contract_class = sierra_contract_class.into_casm_contract_class(false)?; + let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX)?; Ok(casm_contract_class) } pub fn flattened_sierra_to_sierra_contract_class( flattened_sierra: Arc, ) -> starknet_api::state::ContractClass { - let mut entry_point_by_type = + let mut entry_points_by_type = IndexMap::>::with_capacity(3); for sierra_entrypoint in flattened_sierra.entry_points_by_type.constructor.iter() { - entry_point_by_type + entry_points_by_type .entry(starknet_api::state::EntryPointType::Constructor) .or_default() .push(rpc_entry_point_to_starknet_api_entry_point(sierra_entrypoint)); } for sierra_entrypoint in flattened_sierra.entry_points_by_type.external.iter() { - entry_point_by_type + entry_points_by_type .entry(starknet_api::state::EntryPointType::External) .or_default() .push(rpc_entry_point_to_starknet_api_entry_point(sierra_entrypoint)); } for sierra_entrypoint in flattened_sierra.entry_points_by_type.l1_handler.iter() { - entry_point_by_type + entry_points_by_type .entry(starknet_api::state::EntryPointType::L1Handler) .or_default() .push(rpc_entry_point_to_starknet_api_entry_point(sierra_entrypoint)); } starknet_api::state::ContractClass { sierra_program: flattened_sierra.sierra_program.iter().map(|f| Felt252Wrapper(*f).into()).collect(), - entry_point_by_type, + entry_points_by_type, abi: flattened_sierra.abi.clone(), } } @@ -293,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 8b5836696b..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,30 +61,23 @@ 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, - transaction_hash: tx_hash.into(), + 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 9d61aa3db1..df992fa367 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; @@ -158,11 +167,13 @@ where /// Returns the substrate block hash corresponding to the given Starknet block id fn substrate_block_hash_from_starknet_block(&self, block_id: BlockId) -> Result { match block_id { - BlockId::Hash(h) => madara_backend_client::load_hash(self.client.as_ref(), &self.backend, h.into()) - .map_err(|e| { - error!("Failed to load Starknet block hash for Substrate block with hash '{h}': {e}"); - StarknetRpcApiError::BlockNotFound - })?, + BlockId::Hash(h) => { + madara_backend_client::load_hash(self.client.as_ref(), &self.backend, Felt252Wrapper(h).into()) + .map_err(|e| { + error!("Failed to load Starknet block hash for Substrate block with hash '{h}': {e}"); + StarknetRpcApiError::BlockNotFound + })? + } BlockId::Number(n) => self .client .hash(UniqueSaturatedInto::unique_saturated_into(n)) @@ -197,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 @@ -224,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 @@ -274,7 +243,7 @@ where fn predeployed_accounts(&self) -> RpcResult> { let genesis_data = self.genesis_provider.load_genesis_data()?; let block_id = BlockId::Tag(BlockTag::Latest); - let fee_token_address: FieldElement = genesis_data.fee_token_address.0; + let fee_token_address: FieldElement = genesis_data.eth_fee_token_address.0; Ok(genesis_data .predeployed_accounts @@ -334,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)?, }; @@ -347,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); @@ -358,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 @@ -390,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 @@ -420,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(), }) } } @@ -555,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 @@ -567,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)?; @@ -880,10 +833,8 @@ where /// a pending block with transaction hashes, depending on the state of the requested block. /// In case the block is not found, returns a `StarknetRpcApiError` with `BlockNotFound`. fn get_block_with_tx_hashes(&self, block_id: BlockId) -> RpcResult { - let chain_id = self.chain_id()?; - if is_pending_block(block_id) { - let pending_block = self.prepare_pending_block_with_tx_hashes(Felt252Wrapper(chain_id.0))?; + let pending_block = self.prepare_pending_block_with_tx_hashes()?; return Ok(MaybePendingBlockWithTxHashes::PendingBlock(pending_block)); } @@ -894,18 +845,10 @@ where let starknet_block = get_block_by_block_hash(self.client.as_ref(), substrate_block_hash)?; let starknet_version = starknet_block.header().protocol_version; - let l1_gas_price = starknet_block.header().l1_gas_price; 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(FieldElement::from(tx_hash)); - } - 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 { @@ -930,7 +873,7 @@ where new_root: Felt252Wrapper::from(self.backend.temporary_global_state_root_getter()).into(), timestamp: starknet_block.header().block_timestamp, sequencer_address: Felt252Wrapper::from(starknet_block.header().sequencer_address).into(), - l1_gas_price: starknet_block.header().l1_gas_price.into(), + l1_gas_price: todo!(), starknet_version: starknet_version.to_string(), }; @@ -1016,9 +959,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 })?; @@ -1027,7 +973,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, overall_fee: x.0 }) + .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) @@ -1056,17 +1007,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, - overall_fee: fee_estimate.1, + gas_consumed: FieldElement::from(fee_estimate.2), + overall_fee: FieldElement::from(fee_estimate.1), + unit: PriceUnit::Wei, }; Ok(estimate) @@ -1105,21 +1069,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| FieldElement::from(fe)).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. @@ -1141,11 +1091,8 @@ where /// transactions. In case the specified block is not found, returns a `StarknetRpcApiError` with /// `BlockNotFound`. fn get_block_with_txs(&self, block_id: BlockId) -> RpcResult { - let chain_id = self.chain_id()?; - let chain_id = Felt252Wrapper(chain_id.0); - if is_pending_block(block_id) { - let pending_block = self.prepare_pending_block_with_txs(chain_id)?; + let pending_block = self.prepare_pending_block_with_txs()?; return Ok(MaybePendingBlockWithTxs::PendingBlock(pending_block)); } @@ -1158,24 +1105,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| FieldElement::from(h)).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 @@ -1187,7 +1117,7 @@ where timestamp: starknet_block.header().block_timestamp, sequencer_address: Felt252Wrapper::from(starknet_block.header().sequencer_address).into(), transactions, - l1_gas_price: starknet_block.header().l1_gas_price.into(), + l1_gas_price: todo!(), starknet_version: starknet_version.to_string(), }; @@ -1225,7 +1155,7 @@ where let latest_block = self.get_best_block_hash(); let latest_block = get_block_by_block_hash(self.client.as_ref(), latest_block).unwrap_or_default(); - let old_root = self.backend.temporary_global_state_root_getter().into(); + let old_root = Felt252Wrapper::from(self.backend.temporary_global_state_root_getter()).into(); let pending_state_update = PendingStateUpdate { old_root, state_diff }; return Ok(MaybePendingStateUpdate::PendingUpdate(pending_state_update)); @@ -1369,8 +1299,11 @@ where /// - `TOO_MANY_KEYS_IN_FILTER` if there are too many keys in the filter, which may exceed the /// system's capacity. fn get_transaction_by_hash(&self, transaction_hash: FieldElement) -> RpcResult { - let substrate_block_hash_from_db = - self.backend.mapping().block_hash_from_transaction_hash(transaction_hash.into()).map_err(|e| { + let substrate_block_hash_from_db = self + .backend + .mapping() + .block_hash_from_transaction_hash(Felt252Wrapper::from(transaction_hash).into()) + .map_err(|e| { error!("Failed to get transaction's substrate block hash from mapping_db: {e}"); StarknetRpcApiError::TxnHashNotFound })?; @@ -1382,22 +1315,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()) } @@ -1428,21 +1351,22 @@ where &self, transaction_hash: FieldElement, ) -> RpcResult { - let chain_id = self.chain_id()?.0.into(); - let receipt = - match self.backend.mapping().block_hash_from_transaction_hash(transaction_hash.into()).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? - } - // Try to find pending Tx - None => self.get_pending_transaction_receipt(chain_id, transaction_hash).await.map_err(|e| { - error!("Failed to find pending tx with hash: {transaction_hash}: {e}"); - StarknetRpcApiError::TxnHashNotFound - })?, - }; + 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(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? + } + // Try to find pending Tx + None => self.get_pending_transaction_receipt(chain_id, transaction_hash).await.map_err(|e| { + error!("Failed to find pending tx with hash: {transaction_hash}: {e}"); + StarknetRpcApiError::TxnHashNotFound + })?, + }; Ok(receipt) } } @@ -1460,22 +1384,19 @@ where G: GenesisProvider + Send + Sync + 'static, H: HasherT + Send + Sync + 'static, { - fn prepare_pending_block_with_tx_hashes( - &self, - chain_id: Felt252Wrapper, - ) -> Result { + fn prepare_pending_block_with_tx_hashes(&self) -> Result { let parent_hash = self.get_best_block_hash(); 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| tx.compute_hash::(chain_id.0.into(), false).0) + .map(|tx| Felt252Wrapper::from(*get_transaction_hash(tx)).into()) .collect::>(); let pending_block = PendingBlockWithTxHashes { transactions, - l1_gas_price: latest_block_header.l1_gas_price.into(), + l1_gas_price: todo!(), parent_hash: latest_block_header.hash::().into(), sequencer_address: Felt252Wrapper::from(latest_block_header.sequencer_address).into(), starknet_version: latest_block_header.protocol_version.to_string(), @@ -1484,23 +1405,17 @@ where Ok(pending_block) } - fn prepare_pending_block_with_txs( - &self, - chain_id: Felt252Wrapper, - ) -> Result { + fn prepare_pending_block_with_txs(&self) -> Result { let parent_hash = self.get_best_block_hash(); 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, - l1_gas_price: latest_block_header.l1_gas_price.into(), + l1_gas_price: todo!(), parent_hash: latest_block_header.hash::().into(), sequencer_address: Felt252Wrapper::from(latest_block_header.sequencer_address).into(), starknet_version: latest_block_header.protocol_version.to_string(), @@ -1509,7 +1424,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 @@ -1517,14 +1435,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) @@ -1545,15 +1464,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 \ @@ -1563,7 +1474,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)?; @@ -1577,20 +1488,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)?; @@ -1602,54 +1516,66 @@ where let skip_validate = true; // let parent_block_hash = Felt252Wrapper::from().into(); let parent_block_hash = self - .substrate_block_hash_from_starknet_block(BlockId::Hash(block_header.parent_block_hash.into())) + .substrate_block_hash_from_starknet_block(BlockId::Hash( + Felt252Wrapper::from(block_header.parent_block_hash).into(), + )) .map_err(|e| { error!("Parent Block not found: {e}"); StarknetRpcApiError::BlockNotFound })?; 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, @@ -1678,23 +1604,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: FieldElement, - ) -> Result, StarknetRpcApiError> { + tx_hash: TransactionHash, + ) -> Result, StarknetRpcApiError> { let latest_block = self.get_best_block_hash(); - let pending_tx = self - .get_pending_txs(latest_block)? - .iter() - .find(|&tx| tx.compute_hash::(chain_id.0.into(), false).0 == 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) } @@ -1702,7 +1625,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)?; @@ -1717,49 +1640,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, @@ -1846,18 +1776,20 @@ fn revert_error_to_execution_result(revert_error: Option) -> ExecutionRe } fn actual_resources_to_execution_resources(resources: ResourcesMapping) -> ExecutionResources { - let resources = resources.0.into_iter().map(|(k, v)| (k.to_lowercase(), v)).collect::>(); + let resources = + resources.0.into_iter().map(|(k, v)| (k.to_lowercase(), v as u64)).collect::>(); // 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 b0133e25b5..2c9132a6d5 100644 --- a/crates/client/rpc/src/runtime_api.rs +++ b/crates/client/rpc/src/runtime_api.rs @@ -1,4 +1,7 @@ +use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::L1HandlerTransaction; use log::error; pub use mc_rpc_core::utils::*; pub use mc_rpc_core::{ @@ -8,7 +11,6 @@ pub use mc_rpc_core::{ use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; use mp_simulations::SimulationFlags; -use mp_transactions::{HandleL1MessageTransaction, Transaction, UserTransaction}; use pallet_starknet_runtime_api::{ ConvertTransactionRuntimeApi, StarknetRuntimeApi, StarknetTransactionExecutionError, }; @@ -18,9 +20,8 @@ use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use sp_runtime::DispatchError; -use starknet_api::api_core::{ContractAddress, EntryPointSelector}; +use starknet_api::core::{ContractAddress, EntryPointSelector}; use starknet_api::transaction::{Calldata, Event, TransactionHash}; -use starknet_core::types::FieldElement; use crate::{Starknet, StarknetRpcApiError}; @@ -52,8 +53,8 @@ where pub fn do_estimate_message_fee( &self, block_hash: B::Hash, - message: HandleL1MessageTransaction, - ) -> RpcApiResult<(u128, u64, u64)> { + message: L1HandlerTransaction, + ) -> RpcApiResult<(u128, u128, u128)> { self.client .runtime_api() .estimate_message_fee(block_hash, message) @@ -109,7 +110,7 @@ where pub fn convert_tx_to_extrinsic( &self, best_block_hash: ::Hash, - transaction: UserTransaction, + transaction: AccountTransaction, ) -> RpcApiResult { self.client.runtime_api().convert_transaction(best_block_hash, transaction).map_err(|e| { error!("Failed to convert transaction: {:?}", e); @@ -120,8 +121,8 @@ where pub fn estimate_fee( &self, block_hash: B::Hash, - transactions: Vec, - ) -> RpcApiResult> { + transactions: Vec, + ) -> RpcApiResult> { self.client .runtime_api() .estimate_fee(block_hash, transactions) @@ -134,6 +135,7 @@ where StarknetRpcApiError::ContractError }) } + pub fn get_best_block_hash(&self) -> B::Hash { self.client.info().best_hash } @@ -157,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 { @@ -182,28 +181,17 @@ where skip_validate: bool, skip_fee_charge: bool, ) -> RpcApiResult { - let simulations_flags = SimulationFlags { skip_validate, skip_fee_charge }; + let simulations_flags = SimulationFlags { validate: !skip_validate, charge_fee: !skip_fee_charge }; match tx { - Transaction::Declare(tx, contract_class) => { - let tx = UserTransaction::Declare(tx, contract_class); - self.simulate_user_tx(block_hash, tx, simulations_flags) - } - Transaction::DeployAccount(tx) => { - let tx = UserTransaction::DeployAccount(tx); - self.simulate_user_tx(block_hash, tx, simulations_flags) - } - Transaction::Invoke(tx) => { - let tx = UserTransaction::Invoke(tx); - self.simulate_user_tx(block_hash, tx, simulations_flags) - } - Transaction::L1Handler(tx) => self.simulate_l1_tx(block_hash, tx, simulations_flags), + Transaction::AccountTransaction(tx) => self.simulate_user_tx(block_hash, tx, simulations_flags), + Transaction::L1HandlerTransaction(tx) => self.simulate_l1_tx(block_hash, tx, simulations_flags), } } fn simulate_user_tx( &self, block_hash: B::Hash, - tx: UserTransaction, + tx: AccountTransaction, simulations_flags: SimulationFlags, ) -> RpcApiResult { // Simulate a single User Transaction @@ -230,7 +218,7 @@ where fn simulate_l1_tx( &self, block_hash: B::Hash, - tx: HandleL1MessageTransaction, + tx: L1HandlerTransaction, simulations_flags: SimulationFlags, ) -> RpcApiResult { // Simulated a single HandleL1MessageTransaction diff --git a/crates/client/rpc/src/trace_api.rs b/crates/client/rpc/src/trace_api.rs index 058218ae80..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::contract_class::{ContractClass, ContractClassV1}; -use blockifier::execution::entry_point::CallInfo; +use blockifier::execution::call_info::CallInfo; 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::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, }) }) @@ -272,16 +205,16 @@ fn collect_call_info_ordered_messages(call_info: &CallInfo) -> Vec Vec { ordered_events .iter() @@ -316,8 +249,6 @@ fn try_get_function_invocation_from_call_info( let inner_calls = call_info.inner_calls.iter().map(try_get_function_invocation_from_call_info).collect::>()?; - call_info.get_sorted_l2_to_l1_payloads_length()?; - let entry_point_type = match call_info.call.entry_point_type { starknet_api::deprecated_contract_class::EntryPointType::Constructor => { starknet_core::types::EntryPointType::Constructor @@ -336,23 +267,68 @@ fn try_get_function_invocation_from_call_info( }; // The class hash in the call_info is computed during execution and will be set here. - let class_hash = call_info.call.class_hash.expect("Class hash should be computed after execution").0.into(); + let class_hash = + Felt252Wrapper::from(call_info.call.class_hash.expect("Class hash should be computed after execution")) + .0 + .into(); Ok(starknet_core::types::FunctionInvocation { - contract_address: call_info.call.storage_address.0.0.into(), - entry_point_selector: call_info.call.entry_point_selector.0.into(), - calldata: call_info.call.calldata.0.iter().map(|x| (*x).into()).collect(), - caller_address: call_info.call.caller_address.0.0.into(), + contract_address: Felt252Wrapper::from(call_info.call.storage_address).into(), + entry_point_selector: Felt252Wrapper::from(call_info.call.entry_point_selector).into(), + calldata: call_info.call.calldata.0.iter().map(|x| Felt252Wrapper::from(*x).into()).collect(), + caller_address: Felt252Wrapper::from(call_info.call.caller_address).into(), class_hash, entry_point_type, call_type, - result: call_info.execution.retdata.0.iter().map(|x| (*x).into()).collect(), + result: call_info.execution.retdata.0.iter().map(|x| Felt252Wrapper::from(*x).into()).collect(), 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, @@ -429,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/client/settlement/Cargo.toml b/crates/client/settlement/Cargo.toml index 363706cfe4..95ff3538d0 100644 --- a/crates/client/settlement/Cargo.toml +++ b/crates/client/settlement/Cargo.toml @@ -42,6 +42,7 @@ mp-snos-output = { workspace = true, default-features = true } mp-transactions = { workspace = true, default-features = true } starknet-crypto = { workspace = true, default-features = true } starknet_api = { workspace = true, default-features = true } +blockifier = { workspace = true, default-features = true } # Madara pallet-starknet-runtime-api = { workspace = true, default-features = true } diff --git a/crates/client/settlement/src/sync_state.rs b/crates/client/settlement/src/sync_state.rs index 6692e6a9ef..4ac3657bb3 100644 --- a/crates/client/settlement/src/sync_state.rs +++ b/crates/client/settlement/src/sync_state.rs @@ -1,13 +1,13 @@ use std::sync::Arc; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::transaction_execution::Transaction; use futures::StreamExt; use futures_timer::Delay; use mp_block::Block as StarknetBlock; use mp_hashers::HasherT; use mp_messages::{MessageL1ToL2, MessageL2ToL1}; use mp_snos_output::StarknetOsOutput; -use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::Transaction; use pallet_starknet_runtime_api::StarknetRuntimeApi; use sc_client_api::BlockchainEvents; use sp_api::{HeaderT, ProvideRuntimeApi}; @@ -15,7 +15,6 @@ use sp_arithmetic::traits::UniqueSaturatedInto; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use starknet_api::hash::StarkHash; -use starknet_api::transaction::TransactionHash; use crate::errors::Error; use crate::{Result, RetryStrategy, SettlementProvider, SettlementWorker, StarknetSpec, StarknetState}; @@ -251,13 +250,18 @@ where let mut messages_to_l1: Vec = Vec::new(); let mut messages_to_l2: Vec = Vec::new(); - let chain_id = substrate_client.runtime_api().chain_id(substrate_block_hash)?; - for tx in next_block.transactions() { - if let Transaction::L1Handler(l1_handler) = tx { - messages_to_l2.push(l1_handler.clone().into()); + if let Transaction::L1HandlerTransaction(l1_handler) = tx { + messages_to_l2.push(l1_handler.tx.clone().into()); } - let tx_hash = TransactionHash(tx.compute_hash::(chain_id, false).into()); + let tx_hash = match tx { + Transaction::AccountTransaction(tx) => match tx { + AccountTransaction::Declare(tx) => tx.tx_hash, + AccountTransaction::DeployAccount(tx) => tx.tx_hash, + AccountTransaction::Invoke(tx) => tx.tx_hash, + }, + Transaction::L1HandlerTransaction(tx) => tx.tx_hash, + }; substrate_client .runtime_api() .get_tx_messages_to_l1(substrate_block_hash, tx_hash)? diff --git a/crates/client/storage/Cargo.toml b/crates/client/storage/Cargo.toml index 6749879bea..384fd20584 100644 --- a/crates/client/storage/Cargo.toml +++ b/crates/client/storage/Cargo.toml @@ -14,7 +14,7 @@ publish = false repository = "https://github.com/keep-starknet-strange/madara" [dependencies] -blockifier = { workspace = true, features = ["std"] } +blockifier = { workspace = true } frame-support = { workspace = true, features = ["std"] } frame-system = { workspace = true, features = ["std"] } madara-runtime = { workspace = true, features = ["std"] } @@ -30,4 +30,4 @@ sp-io = { workspace = true, features = ["std"] } sp-runtime = { workspace = true, features = ["std"] } sp-storage = { workspace = true, features = ["std"] } starknet-core = { workspace = true, features = ["std"] } -starknet_api = { workspace = true, features = ["std"] } +starknet_api = { workspace = true } diff --git a/crates/client/storage/src/overrides/mod.rs b/crates/client/storage/src/overrides/mod.rs index 04096d5afc..539a5923ee 100644 --- a/crates/client/storage/src/overrides/mod.rs +++ b/crates/client/storage/src/overrides/mod.rs @@ -10,7 +10,7 @@ use sc_client_api::{Backend, HeaderBackend, StorageProvider}; use sp_api::ProvideRuntimeApi; use sp_io::hashing::twox_128; use sp_runtime::traits::Block as BlockT; -use starknet_api::api_core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; use starknet_api::transaction::{Event as StarknetEvent, TransactionHash}; diff --git a/crates/client/storage/src/overrides/schema_v1_override.rs b/crates/client/storage/src/overrides/schema_v1_override.rs index af8182b3d6..67643848e9 100644 --- a/crates/client/storage/src/overrides/schema_v1_override.rs +++ b/crates/client/storage/src/overrides/schema_v1_override.rs @@ -12,7 +12,7 @@ use sc_client_api::backend::{Backend, StorageProvider}; use sp_blockchain::HeaderBackend; use sp_runtime::traits::Block as BlockT; use sp_storage::StorageKey; -use starknet_api::api_core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey as StarknetStorageKey; use starknet_api::transaction::{Event as StarknetEvent, TransactionHash}; diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index f3a85edcac..667f11b466 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -94,10 +94,7 @@ mc-storage = { workspace = true } pallet-starknet = { workspace = true } pallet-starknet-runtime-api = { workspace = true } starknet-core = { workspace = true } -starknet_api = { workspace = true, features = [ - "scale-info", - "parity-scale-codec", -] } +starknet_api = { workspace = true } # Madara utils mc-genesis-data-provider = { workspace = true } diff --git a/crates/pallets/starknet/Cargo.toml b/crates/pallets/starknet/Cargo.toml index 9293b22b36..a1d57709da 100644 --- a/crates/pallets/starknet/Cargo.toml +++ b/crates/pallets/starknet/Cargo.toml @@ -38,15 +38,10 @@ mp-transactions = { workspace = true, features = ["scale-info"] } blockifier = { workspace = true, features = [ "testing", - "parity-scale-codec", - "scale-info", ] } starknet-core = { workspace = true } starknet-crypto = { workspace = true, features = ["alloc"] } -starknet_api = { workspace = true, features = [ - "scale-info", - "parity-scale-codec", -] } +starknet_api = { workspace = true } # Substrate frame frame-benchmarking = { workspace = true, optional = true } @@ -62,14 +57,12 @@ sp-inherents = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +cairo-vm = { workspace = true } # Frame pallets # Other third party dependencies -cairo-lang-casm-contract-class = { workspace = true, optional = true, features = [ - "std", -] } +cairo-lang-starknet-classes = { workspace = true, optional = true } derive_more = { workspace = true } -hashbrown = { workspace = true } hex = { workspace = true } indexmap = { workspace = true } log = { workspace = true } @@ -108,15 +101,14 @@ std = [ "sp-inherents/std", # Starknet "starknet-crypto/std", - "blockifier/std", "mp-felt/std", "mp-sequencer-address/std", # Other third party dependencies "dep:reqwest", - "dep:cairo-lang-casm-contract-class", "parity-scale-codec/std", "starknet-core/std", "mp-simulations/std", + "cairo-lang-starknet-classes" ] runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] try-runtime = ["frame-support/try-runtime"] diff --git a/crates/pallets/starknet/runtime_api/Cargo.toml b/crates/pallets/starknet/runtime_api/Cargo.toml index 5762c6dcca..0f8d83ed34 100644 --- a/crates/pallets/starknet/runtime_api/Cargo.toml +++ b/crates/pallets/starknet/runtime_api/Cargo.toml @@ -22,16 +22,10 @@ mp-transactions = { workspace = true, features = [ ] } # Starknet -blockifier = { workspace = true, features = [ - "parity-scale-codec", - "scale-info", -] } +blockifier = { workspace = true } hashbrown = { workspace = true } starknet-core = { workspace = true } -starknet_api = { workspace = true, features = [ - "scale-info", - "parity-scale-codec", -] } +starknet_api = { workspace = true } # Substrate parity-scale-codec = { workspace = true, features = ["derive"] } @@ -46,8 +40,6 @@ default = ["std"] std = [ "mp-felt/std", "mp-transactions/std", - "blockifier/std", - "starknet_api/std", "sp-api/std", "sp-runtime/std", "sp-arithmetic/std", diff --git a/crates/pallets/starknet/runtime_api/src/lib.rs b/crates/pallets/starknet/runtime_api/src/lib.rs index 218a0e0c33..ebfb6787b6 100644 --- a/crates/pallets/starknet/runtime_api/src/lib.rs +++ b/crates/pallets/starknet/runtime_api/src/lib.rs @@ -5,25 +5,24 @@ // Specifically, the macro generates a trait (`StarknetRuntimeApi`) with unused type parameters. #![allow(clippy::extra_unused_type_parameters)] -use alloc::sync::Arc; - +use blockifier::context::{BlockContext, FeeTokenAddresses}; use blockifier::execution::contract_class::ContractClass; use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::L1HandlerTransaction; use mp_felt::Felt252Wrapper; -use mp_transactions::{HandleL1MessageTransaction, Transaction, UserOrL1HandlerTransaction, UserTransaction}; use sp_api::BlockT; pub extern crate alloc; -use alloc::string::String; use alloc::vec::Vec; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags, TransactionSimulationResult}; use sp_runtime::DispatchError; -use starknet_api::api_core::{ChainId, ClassHash, ContractAddress, EntryPointSelector, Nonce}; -use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::StorageKey; -use starknet_api::transaction::{Calldata, Event as StarknetEvent, Fee, MessageToL1, TransactionHash}; +use starknet_api::transaction::{Calldata, Event as StarknetEvent, MessageToL1, TransactionHash}; #[derive(parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)] pub enum StarknetTransactionExecutionError { @@ -53,15 +52,15 @@ sp_api::decl_runtime_apis! { /// Returns the Starknet config hash. fn config_hash() -> StarkHash; /// Returns the fee token address. - fn fee_token_address() -> ContractAddress; + fn fee_token_addresses() -> FeeTokenAddresses; /// Returns fee estimate - fn estimate_fee(transactions: Vec) -> Result, DispatchError>; + fn estimate_fee(transactions: Vec) -> Result, DispatchError>; /// Returns message fee estimate - fn estimate_message_fee(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError>; + fn estimate_message_fee(message: L1HandlerTransaction) -> Result<(u128, u128, u128), DispatchError>; /// Simulates single L1 Message and returns its trace - fn simulate_message(message: HandleL1MessageTransaction, simulation_flags: SimulationFlags) -> Result, DispatchError>; + fn simulate_message(message: L1HandlerTransaction, simulation_flags: SimulationFlags) -> Result, DispatchError>; /// Simulates transactions and returns their trace - fn simulate_transactions(transactions: Vec, simulation_flags: SimulationFlags) -> Result, DispatchError>; + fn simulate_transactions(transactions: Vec, simulation_flags: SimulationFlags) -> Result, DispatchError>; /// Filters extrinsic transactions to return only Starknet transactions /// /// To support runtime upgrades, the client must be unaware of the specific extrinsic @@ -72,9 +71,9 @@ sp_api::decl_runtime_apis! { /// client to operate seamlessly while abstracting the extrinsic complexity. fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec; /// 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 re_execute_transactions(transactions: Vec) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError>; - fn get_index_and_tx_for_tx_hash(xts: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: Felt252Wrapper) -> 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 @@ -91,70 +90,12 @@ sp_api::decl_runtime_apis! { pub trait ConvertTransactionRuntimeApi { /// Converts the transaction to an UncheckedExtrinsic for submission to the pool. - fn convert_transaction(transaction: UserTransaction) -> ::Extrinsic; + fn convert_transaction(transaction: AccountTransaction) -> ::Extrinsic; /// Converts the L1 Message transaction to an UncheckedExtrinsic for submission to the pool. - fn convert_l1_transaction(transaction: HandleL1MessageTransaction, fee: Fee) -> ::Extrinsic; + fn convert_l1_transaction(transaction: L1HandlerTransaction) -> ::Extrinsic; /// Converts the DispatchError to an understandable error for the client fn convert_error(error: DispatchError) -> StarknetTransactionExecutionError; } } - -#[derive(Clone, Debug, parity_scale_codec::Encode, parity_scale_codec::Decode, scale_info::TypeInfo)] -pub struct BlockContext { - pub chain_id: String, - pub block_number: u64, - pub block_timestamp: u64, - - // Fee-related. - pub sequencer_address: ContractAddress, - pub fee_token_address: ContractAddress, - pub vm_resource_fee_cost: Vec<(String, sp_arithmetic::fixed_point::FixedU128)>, - pub gas_price: u128, // In wei. - - // Limits. - pub invoke_tx_max_n_steps: u32, - pub validate_max_n_steps: u32, - pub max_recursion_depth: u32, -} - -#[cfg(feature = "std")] -use std::collections::HashMap; - -#[cfg(not(feature = "std"))] -use hashbrown::HashMap; - -impl From for blockifier::block_context::BlockContext { - fn from(value: BlockContext) -> Self { - Self { - chain_id: ChainId(value.chain_id), - block_number: BlockNumber(value.block_number), - block_timestamp: BlockTimestamp(value.block_timestamp), - sequencer_address: value.sequencer_address, - fee_token_address: value.fee_token_address, - vm_resource_fee_cost: Arc::new(HashMap::from_iter(value.vm_resource_fee_cost)), - gas_price: value.gas_price, - invoke_tx_max_n_steps: value.invoke_tx_max_n_steps, - validate_max_n_steps: value.validate_max_n_steps, - max_recursion_depth: value.max_recursion_depth, - } - } -} - -impl From for BlockContext { - fn from(value: blockifier::block_context::BlockContext) -> Self { - Self { - chain_id: value.chain_id.0, - block_number: value.block_number.0, - block_timestamp: value.block_timestamp.0, - sequencer_address: value.sequencer_address, - fee_token_address: value.fee_token_address, - vm_resource_fee_cost: Vec::from_iter(value.vm_resource_fee_cost.iter().map(|(k, v)| (k.clone(), *v))), - gas_price: value.gas_price, - invoke_tx_max_n_steps: value.invoke_tx_max_n_steps, - validate_max_n_steps: value.validate_max_n_steps, - max_recursion_depth: value.max_recursion_depth, - } - } -} diff --git a/crates/pallets/starknet/src/blockifier_state_adapter.rs b/crates/pallets/starknet/src/blockifier_state_adapter.rs index 84eb6e39f7..12ecb66584 100644 --- a/crates/pallets/starknet/src/blockifier_state_adapter.rs +++ b/crates/pallets/starknet/src/blockifier_state_adapter.rs @@ -1,19 +1,20 @@ use alloc::collections::{BTreeMap, BTreeSet}; use core::marker::PhantomData; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use blockifier::execution::contract_class::ContractClass; -use blockifier::state::cached_state::{CommitmentStateDiff, ContractStorageKey, StateChangesCount, StorageView}; +use blockifier::state::cached_state::{CachedState, CommitmentStateDiff, GlobalContractCache, StateChangesCount}; use blockifier::state::errors::StateError; use blockifier::state::state_api::{State, StateReader, StateResult}; use indexmap::IndexMap; use mp_felt::Felt252Wrapper; -use mp_state::StateChanges; -use starknet_api::api_core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use mp_transactions::execution::SetArbitraryNonce; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; use starknet_crypto::FieldElement; +use crate::types::ContractStorageKey; use crate::{Config, Pallet}; /// Empty struct that implements the traits needed by the blockifier/starknet in rust. @@ -25,68 +26,59 @@ pub struct BlockifierStateAdapter { storage_update: BTreeMap, class_hash_update: usize, compiled_class_hash_update: usize, - state_cache: StateCache, + visited_pcs: HashMap>, _phantom: PhantomData, } -impl StateChanges for BlockifierStateAdapter -where - T: Config, -{ - fn count_state_changes(&self) -> StateChangesCount { - let keys = self.storage_update.keys(); - let n_contract_updated = BTreeSet::from_iter(keys.clone().map(|&(contract_address, _)| contract_address)).len(); - StateChangesCount { - n_modified_contracts: n_contract_updated, - n_storage_updates: keys.len(), - n_class_hash_updates: self.class_hash_update, - n_compiled_class_hash_updates: self.compiled_class_hash_update, - } - } -} - impl Default for BlockifierStateAdapter { fn default() -> Self { Self { storage_update: BTreeMap::default(), class_hash_update: usize::default(), compiled_class_hash_update: usize::default(), - state_cache: StateCache::default(), + visited_pcs: Default::default(), _phantom: PhantomData, } } } impl StateReader for BlockifierStateAdapter { - fn get_storage_at(&mut self, contract_address: ContractAddress, key: StorageKey) -> StateResult { + fn get_storage_at(&self, contract_address: ContractAddress, key: StorageKey) -> StateResult { let contract_storage_key: ContractStorageKey = (contract_address, key); Ok(Pallet::::storage(contract_storage_key)) } - fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { Ok(Pallet::::nonce(contract_address)) } - fn get_class_hash_at(&mut self, contract_address: ContractAddress) -> StateResult { - Ok(Pallet::::contract_class_hash_by_address(contract_address)) + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + Ok(ClassHash(Pallet::::contract_class_hash_by_address(contract_address))) } - fn get_compiled_contract_class(&mut self, class_hash: &ClassHash) -> StateResult { - Pallet::::contract_class_by_class_hash(class_hash).ok_or(StateError::UndeclaredClassHash(*class_hash)) + fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { + Pallet::::contract_class_by_class_hash(class_hash.0).ok_or(StateError::UndeclaredClassHash(class_hash)) } - fn get_compiled_class_hash(&mut self, class_hash: ClassHash) -> StateResult { - Pallet::::compiled_class_hash_by_class_hash(class_hash).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.0).ok_or(StateError::UndeclaredClassHash(class_hash)) } } impl State for BlockifierStateAdapter { - fn set_storage_at(&mut self, contract_address: ContractAddress, key: StorageKey, value: StarkFelt) { + fn set_storage_at( + &mut self, + contract_address: ContractAddress, + key: StorageKey, + value: StarkFelt, + ) -> StateResult<()> { let contract_storage_key: ContractStorageKey = (contract_address, key); self.storage_update.insert(contract_storage_key, value); crate::StorageView::::insert(contract_storage_key, value); + + Ok(()) } fn increment_nonce(&mut self, contract_address: ContractAddress) -> StateResult<()> { @@ -102,13 +94,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); + fn set_contract_class(&mut self, class_hash: ClassHash, contract_class: ContractClass) -> StateResult<()> { + crate::ContractClasses::::insert(class_hash.0, contract_class); Ok(()) } @@ -119,120 +111,21 @@ 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(()) } - /// As the state is updated during the execution, return an empty [StateDiff] - /// - /// There is no reason to use it in the current implementation of the trait - fn to_state_diff(&self) -> CommitmentStateDiff { - CommitmentStateDiff { - address_to_class_hash: IndexMap::with_capacity_and_hasher(0, Default::default()), - address_to_nonce: IndexMap::with_capacity_and_hasher(0, Default::default()), - storage_updates: IndexMap::with_capacity_and_hasher(0, Default::default()), - class_hash_to_compiled_class_hash: IndexMap::with_capacity_and_hasher(0, Default::default()), - } - } -} - -#[derive(Debug, Default, PartialEq)] -struct StateCache { - // Reader's cached information; initial values, read before any write operation (per cell). - nonce_initial_values: IndexMap, - class_hash_initial_values: IndexMap, - storage_initial_values: IndexMap, - compiled_class_hash_initial_values: IndexMap, - - // Writer's cached information. - nonce_writes: IndexMap, - class_hash_writes: IndexMap, - storage_writes: IndexMap, - compiled_class_hash_writes: IndexMap, -} - -impl StateCache { - fn get_storage_at(&self, contract_address: ContractAddress, key: StorageKey) -> Option<&StarkFelt> { - let contract_storage_key = (contract_address, key); - self.storage_writes - .get(&contract_storage_key) - .or_else(|| self.storage_initial_values.get(&contract_storage_key)) - } - - fn get_nonce_at(&self, contract_address: ContractAddress) -> Option<&Nonce> { - self.nonce_writes.get(&contract_address).or_else(|| self.nonce_initial_values.get(&contract_address)) - } - - pub fn set_storage_initial_value(&mut self, contract_address: ContractAddress, key: StorageKey, value: StarkFelt) { - let contract_storage_key = (contract_address, key); - self.storage_initial_values.insert(contract_storage_key, value); - } - - fn set_storage_value(&mut self, contract_address: ContractAddress, key: StorageKey, value: StarkFelt) { - let contract_storage_key = (contract_address, key); - self.storage_writes.insert(contract_storage_key, value); - } - - fn set_nonce_initial_value(&mut self, contract_address: ContractAddress, nonce: Nonce) { - self.nonce_initial_values.insert(contract_address, nonce); - } - - fn set_nonce_value(&mut self, contract_address: ContractAddress, nonce: Nonce) { - self.nonce_writes.insert(contract_address, nonce); - } - - fn get_class_hash_at(&self, contract_address: ContractAddress) -> Option<&ClassHash> { - self.class_hash_writes.get(&contract_address).or_else(|| self.class_hash_initial_values.get(&contract_address)) - } - - fn set_class_hash_initial_value(&mut self, contract_address: ContractAddress, class_hash: ClassHash) { - self.class_hash_initial_values.insert(contract_address, class_hash); - } - - fn set_class_hash_write(&mut self, contract_address: ContractAddress, class_hash: ClassHash) { - self.class_hash_writes.insert(contract_address, class_hash); - } - - fn get_compiled_class_hash(&self, class_hash: ClassHash) -> Option<&CompiledClassHash> { - self.compiled_class_hash_writes - .get(&class_hash) - .or_else(|| self.compiled_class_hash_initial_values.get(&class_hash)) - } - - fn set_compiled_class_hash_initial_value(&mut self, class_hash: ClassHash, compiled_class_hash: CompiledClassHash) { - self.compiled_class_hash_initial_values.insert(class_hash, compiled_class_hash); - } - - fn set_compiled_class_hash_write(&mut self, class_hash: ClassHash, compiled_class_hash: CompiledClassHash) { - self.compiled_class_hash_writes.insert(class_hash, compiled_class_hash); - } - - fn get_storage_updates(&self) -> HashMap { - HashMap::from_iter(subtract_mappings(&self.storage_writes, &self.storage_initial_values)) - } - - fn get_class_hash_updates(&self) -> IndexMap { - subtract_mappings(&self.class_hash_writes, &self.class_hash_initial_values) - } - - fn get_nonce_updates(&self) -> IndexMap { - subtract_mappings(&self.nonce_writes, &self.nonce_initial_values) - } - - fn get_compiled_class_hash_updates(&self) -> IndexMap { - subtract_mappings(&self.compiled_class_hash_writes, &self.compiled_class_hash_initial_values) + fn add_visited_pcs(&mut self, class_hash: ClassHash, pcs: &std::collections::HashSet) { + self.visited_pcs.entry(class_hash).or_default().extend(pcs); } } -pub struct CachedBlockifierStateAdapter(pub BlockifierStateAdapter); +pub struct CachedBlockifierStateAdapter(pub CachedState>); -impl StateChanges for CachedBlockifierStateAdapter -where - T: Config, -{ - fn count_state_changes(&self) -> StateChangesCount { - self.0.count_state_changes() +impl Default for CachedBlockifierStateAdapter { + fn default() -> Self { + Self(CachedState::new(BlockifierStateAdapter::default(), GlobalContractCache::new(10))) } } @@ -240,25 +133,28 @@ impl State for CachedBlockifierStateAdapter where T: Config, { - fn set_storage_at(&mut self, contract_address: ContractAddress, key: StorageKey, value: StarkFelt) { - self.0.state_cache.set_storage_value(contract_address, key, value); - self.0.set_storage_at(contract_address, key, value); + fn set_storage_at( + &mut self, + contract_address: ContractAddress, + key: StorageKey, + value: StarkFelt, + ) -> StateResult<()> { + self.0.set_storage_at(contract_address, key, value) } fn increment_nonce(&mut self, contract_address: ContractAddress) -> StateResult<()> { - let current_nonce = Pallet::::nonce(contract_address); - let current_nonce: FieldElement = Felt252Wrapper::from(current_nonce.0).into(); - let new_nonce: Nonce = Felt252Wrapper(current_nonce + FieldElement::ONE).into(); - self.0.state_cache.set_nonce_value(contract_address, new_nonce); self.0.increment_nonce(contract_address) + // let current_nonce = Pallet::::nonce(contract_address); + // let current_nonce: FieldElement = Felt252Wrapper::from(current_nonce.0).into(); + // let new_nonce: Nonce = Felt252Wrapper(current_nonce + FieldElement::ONE).into(); + // self.0.state_cache.set_nonce_value(contract_address, new_nonce); } fn set_class_hash_at(&mut self, contract_address: ContractAddress, class_hash: ClassHash) -> StateResult<()> { - self.0.state_cache.set_class_hash_write(contract_address, class_hash); self.0.set_class_hash_at(contract_address, class_hash) } - fn set_contract_class(&mut self, class_hash: &ClassHash, contract_class: ContractClass) -> StateResult<()> { + fn set_contract_class(&mut self, class_hash: ClassHash, contract_class: ContractClass) -> StateResult<()> { self.0.set_contract_class(class_hash, contract_class) } @@ -267,25 +163,11 @@ where class_hash: ClassHash, compiled_class_hash: CompiledClassHash, ) -> StateResult<()> { - self.0.state_cache.set_compiled_class_hash_write(class_hash, compiled_class_hash); self.0.set_compiled_class_hash(class_hash, compiled_class_hash) } - fn to_state_diff(&self) -> CommitmentStateDiff { - type StorageDiff = IndexMap>; - - let state_cache = &self.0.state_cache; - let class_hash_updates = state_cache.get_class_hash_updates(); - let storage_diffs = state_cache.get_storage_updates(); - let nonces = state_cache.get_nonce_updates(); - let declared_classes = state_cache.get_compiled_class_hash_updates(); - - CommitmentStateDiff { - address_to_class_hash: class_hash_updates, - storage_updates: StorageDiff::from(StorageView(storage_diffs)), - class_hash_to_compiled_class_hash: declared_classes, - address_to_nonce: nonces, - } + fn add_visited_pcs(&mut self, class_hash: starknet_api::core::ClassHash, pcs: &std::collections::HashSet) { + self.0.visited_pcs.entry(class_hash).or_default().extend(pcs); } } @@ -293,40 +175,24 @@ impl StateReader for CachedBlockifierStateAdapter where T: Config, { - fn get_storage_at(&mut self, contract_address: ContractAddress, key: StorageKey) -> StateResult { - let storage_value = self.0.get_storage_at(contract_address, key)?; - if self.0.state_cache.get_storage_at(contract_address, key).is_none() { - self.0.state_cache.set_storage_initial_value(contract_address, key, storage_value); - } - Ok(storage_value) + fn get_storage_at(&self, contract_address: ContractAddress, key: StorageKey) -> StateResult { + self.0.get_storage_at(contract_address, key) } - fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { - let nonce = self.0.get_nonce_at(contract_address)?; - if self.0.state_cache.get_nonce_at(contract_address).is_none() { - self.0.state_cache.set_nonce_initial_value(contract_address, nonce); - } - Ok(nonce) + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_nonce_at(contract_address) } - fn get_class_hash_at(&mut self, contract_address: ContractAddress) -> StateResult { - let class_hash = self.0.get_class_hash_at(contract_address)?; - if self.0.state_cache.get_class_hash_at(contract_address).is_none() { - self.0.state_cache.set_class_hash_initial_value(contract_address, class_hash); - } - Ok(class_hash) + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_class_hash_at(contract_address) } - fn get_compiled_contract_class(&mut self, class_hash: &ClassHash) -> StateResult { + fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { self.0.get_compiled_contract_class(class_hash) } - fn get_compiled_class_hash(&mut self, class_hash: ClassHash) -> StateResult { - let compiled_class_hash = self.0.get_compiled_class_hash(class_hash)?; - if self.0.state_cache.get_compiled_class_hash(class_hash).is_none() { - self.0.state_cache.set_compiled_class_hash_initial_value(class_hash, compiled_class_hash); - } - Ok(compiled_class_hash) + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_class_hash(class_hash) } } @@ -340,3 +206,11 @@ where { lhs.iter().filter(|(k, v)| rhs.get(*k) != Some(v)).map(|(k, v)| (k.clone(), v.clone())).collect() } + +impl SetArbitraryNonce for BlockifierStateAdapter { + fn set_nonce_at(&self, contract_address: ContractAddress, nonce: Nonce) -> StateResult<()> { + crate::Nonces::::insert(contract_address, nonce); + + Ok(()) + } +} diff --git a/crates/pallets/starknet/src/genesis_loader.rs b/crates/pallets/starknet/src/genesis_loader.rs index b824917fbc..bb0fa0d9b2 100644 --- a/crates/pallets/starknet/src/genesis_loader.rs +++ b/crates/pallets/starknet/src/genesis_loader.rs @@ -16,6 +16,7 @@ impl From for GenesisConfig { .into_iter() .map(|(hash, class)| { let hash = Felt252Wrapper(hash.0).into(); + log::debug!("loading: {:?}", class); match class { ContractClass::Path { path, version } => ( hash, @@ -27,7 +28,6 @@ impl From for GenesisConfig { version, ), ), - ContractClass::Class(class) => (hash, class), } }) .collect::>(); @@ -64,14 +64,14 @@ impl From for GenesisConfig { (key, value) }) .collect::>(); - let fee_token_address = Felt252Wrapper(loader.data().fee_token_address.0).into(); GenesisConfig { contracts, contract_classes, sierra_to_casm_class_hash, storage, - fee_token_address, + strk_fee_token_address: Felt252Wrapper(loader.data().strk_fee_token_address.0).into(), + eth_fee_token_address: Felt252Wrapper(loader.data().eth_fee_token_address.0).into(), ..Default::default() } } @@ -87,12 +87,13 @@ impl From for GenesisConfig { /// /// `ContractClassV1` needs to be read in Casm and then converted to Contract Class V1 pub(crate) fn read_contract_class_from_json(json_str: &str, version: u8) -> StarknetContractClass { + // println!("json_str: {}", json_str); if version == 0 { return StarknetContractClass::V0( serde_json::from_str(json_str).expect("`json_str` should be deserializable into the correct ContracClass"), ); } else if version == 1 { - let casm_contract_class: cairo_lang_casm_contract_class::CasmContractClass = + let casm_contract_class: cairo_lang_starknet_classes::casm_contract_class::CasmContractClass = serde_json::from_str(json_str).expect("`json_str` should be deserializable into the CasmContracClass"); return StarknetContractClass::V1( casm_contract_class.try_into().expect("the CasmContractClass should produce a valid ContractClassV1"), @@ -125,7 +126,7 @@ mod tests { let contract_address = FieldElement::from(2u8).into(); let storage_key = FieldElement::from(3u8).into(); let storage_value = FieldElement::from(4u8).into(); - let fee_token_address = FieldElement::from(5u8).into(); + let fee_token_address: HexFelt = FieldElement::from(5u8).into(); let genesis_loader = GenesisData { contract_classes: vec![(class_hash, class)], @@ -136,14 +137,15 @@ mod tests { contracts: vec![(contract_address, class_hash)], predeployed_accounts: Vec::new(), storage: vec![((contract_address, storage_key), storage_value)], - fee_token_address, + strk_fee_token_address: fee_token_address.clone(), + eth_fee_token_address: fee_token_address, }; // When let serialized_loader = serde_json::to_string(&genesis_loader).unwrap(); // Then - let expected = r#"{"contract_classes":[["0x1",{"path":"cairo-contracts/ERC20.json","version":0}]],"sierra_class_hash_to_casm_class_hash":[["0x2a","0x1"]],"contracts":[["0x2","0x1"]],"predeployed_accounts":[],"storage":[[["0x2","0x3"],"0x4"]],"fee_token_address":"0x5"}"#; + let expected = r#"{"contract_classes":[["0x1",{"path":"cairo-contracts/ERC20.json","version":0}]],"sierra_class_hash_to_casm_class_hash":[["0x2a","0x1"]],"contracts":[["0x2","0x1"]],"predeployed_accounts":[],"storage":[[["0x2","0x3"],"0x4"]],"strk_fee_token_address":"0x5","eth_fee_token_address":"0x5"}"#; assert_eq!(expected, serialized_loader); } } diff --git a/crates/pallets/starknet/src/lib.rs b/crates/pallets/starknet/src/lib.rs index b50873a2d3..91d442d13f 100644 --- a/crates/pallets/starknet/src/lib.rs +++ b/crates/pallets/starknet/src/lib.rs @@ -32,6 +32,8 @@ // Ensure we're `no_std` when compiling for Wasm. #![allow(clippy::large_enum_variant)] +use std::sync::Arc; + /// Starknet pallet. /// Definition of the pallet's runtime storage items, events, errors, and dispatchable /// functions. @@ -40,8 +42,6 @@ pub use pallet::*; /// An adapter for the blockifier state related traits pub mod blockifier_state_adapter; -/// The implementation of the execution configuration. -pub mod execution_config; #[cfg(feature = "std")] pub mod genesis_loader; /// Simulation, estimations and execution trace logic. @@ -63,44 +63,49 @@ use alloc::string::String; use alloc::vec; use alloc::vec::Vec; -use blockifier::block_context::BlockContext; +use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses, TransactionContext}; +use blockifier::execution::call_info::CallInfo; use blockifier::execution::contract_class::ContractClass; -use blockifier::execution::entry_point::{ - CallEntryPoint, CallInfo, CallType, EntryPointExecutionContext, ExecutionResources, -}; +use blockifier::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; use blockifier::execution::errors::{EntryPointExecutionError, PreExecutionError}; -use blockifier::state::cached_state::ContractStorageKey; -use blockifier_state_adapter::BlockifierStateAdapter; +use blockifier::state::cached_state::{CachedState, GlobalContractCache}; +use blockifier::state::state_api::{StateReader, StateResult}; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::objects::{DeprecatedTransactionInfo, TransactionInfo}; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::{ + DeclareTransaction, DeployAccountTransaction, InvokeTransaction, L1HandlerTransaction, +}; +use blockifier::versioned_constants::VersionedConstants; +use blockifier_state_adapter::{BlockifierStateAdapter, CachedBlockifierStateAdapter}; use frame_support::pallet_prelude::*; use frame_support::traits::Time; use frame_system::pallet_prelude::*; use mp_block::{Block as StarknetBlock, Header as StarknetHeader}; use mp_digest_log::MADARA_ENGINE_ID; -use mp_fee::{ResourcePrice, INITIAL_GAS}; use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; use mp_sequencer_address::{InherentError, InherentType, DEFAULT_SEQUENCER_ADDRESS, INHERENT_IDENTIFIER}; use mp_storage::{StarknetStorageSchemaVersion, PALLET_STARKNET_SCHEMA}; -use mp_transactions::execution::Execute; -use mp_transactions::{ - DeclareTransaction, DeployAccountTransaction, HandleL1MessageTransaction, InvokeTransaction, Transaction, - UserOrL1HandlerTransaction, UserTransaction, +use mp_transactions::execution::{ + execute_l1_handler_transaction, run_non_revertible_transaction, run_revertible_transaction, }; use sp_runtime::traits::UniqueSaturatedInto; use sp_runtime::DigestItem; -use starknet_api::api_core::{ChainId, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::block::{BlockNumber, BlockTimestamp}; +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; -use starknet_api::transaction::{Calldata, Event as StarknetEvent, Fee, MessageToL1, TransactionHash}; +use starknet_api::transaction::{ + Calldata, Event as StarknetEvent, Fee, MessageToL1, TransactionHash, TransactionVersion, +}; use starknet_crypto::FieldElement; use transaction_validation::TxPriorityInfo; use crate::alloc::string::ToString; -use crate::execution_config::RuntimeExecutionConfigBuilder; -use crate::types::{CasmClassHash, SierraClassHash, SierraOrCasmClassHash, StorageSlot}; - +use crate::types::{CasmClassHash, ContractStorageKey, SierraClassHash, SierraOrCasmClassHash, StorageSlot}; pub(crate) const LOG_TARGET: &str = "runtime::starknet"; pub const ETHEREUM_EXECUTION_RPC: &[u8] = b"starknet::ETHEREUM_EXECUTION_RPC"; @@ -121,6 +126,7 @@ macro_rules! log { #[frame_support::pallet] pub mod pallet { + use super::*; #[pallet::pallet] @@ -137,7 +143,7 @@ pub mod pallet { type TimestampProvider: Time; /// The gas price #[pallet::constant] - type L1GasPrice: Get; + type L1GasPrices: Get; /// A configuration for base priority of unsigned transactions. /// /// This is exposed so that it can be tuned for particular runtime, when @@ -301,8 +307,8 @@ pub mod pallet { /// The address of the fee token ERC20 contract. #[pallet::storage] #[pallet::unbounded] - #[pallet::getter(fn fee_token_address)] - pub(super) type FeeTokenAddress = StorageValue<_, ContractAddress, ValueQuery>; + #[pallet::getter(fn fee_token_addresses)] + pub(super) type FeeTokens = StorageValue<_, FeeTokenAddresses, ValueQuery>; /// Current sequencer address. #[pallet::storage] @@ -331,18 +337,19 @@ 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. - pub fee_token_address: ContractAddress, + pub strk_fee_token_address: ContractAddress, + pub eth_fee_token_address: ContractAddress, pub _phantom: PhantomData, } @@ -354,7 +361,8 @@ pub mod pallet { sierra_to_casm_class_hash: vec![], contract_classes: vec![], storage: vec![], - fee_token_address: ContractAddress::default(), + strk_fee_token_address: Default::default(), + eth_fee_token_address: Default::default(), _phantom: PhantomData, } } @@ -370,26 +378,27 @@ 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, ); + println!("genesis deploying contract with class {class_hash:?} at address {address:?}"); - ContractClassHashes::::insert(address, class_hash); + ContractClassHashes::::insert(address, class_hash.0); } for (key, value) in self.storage.iter() { @@ -398,7 +407,10 @@ pub mod pallet { LastKnownEthBlock::::set(None); // Set the fee token address from the genesis config. - FeeTokenAddress::::set(self.fee_token_address); + FeeTokens::::set(FeeTokenAddresses { + strk_fee_token_address: self.strk_fee_token_address, + eth_fee_token_address: self.eth_fee_token_address, + }); SeqAddrUpdate::::put(true); } } @@ -430,6 +442,7 @@ pub mod pallet { FailedToCreateATransactionalStorageExecution, L1MessageAlreadyExecuted, MissingL1GasUsage, + QueryTransactionCannotBeExecuted, } /// The Starknet pallet external functions. @@ -477,40 +490,45 @@ pub mod pallet { #[pallet::call_index(1)] #[pallet::weight({0})] pub fn invoke(origin: OriginFor, transaction: InvokeTransaction) -> DispatchResult { + ensure!(!transaction.only_query, Error::::QueryTransactionCannotBeExecuted); // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; - let input_transaction = transaction; - - let chain_id = Self::chain_id(); - let transaction = input_transaction.into_executable::(chain_id, false); - let sender_address = match &transaction.tx { starknet_api::transaction::InvokeTransaction::V0(tx) => tx.contract_address, starknet_api::transaction::InvokeTransaction::V1(tx) => tx.sender_address, + starknet_api::transaction::InvokeTransaction::V3(tx) => tx.sender_address, }; // Check if contract is deployed ensure!(ContractClassHashes::::contains_key(sender_address), Error::::AccountNotDeployed); + // Init caches + let mut state = BlockifierStateAdapter::::default(); + let block_context = Self::get_block_context(); + let charge_fee = !::DisableTransactionFee::get(); + // Execute - let tx_execution_infos = transaction - .execute( - &mut BlockifierStateAdapter::::default(), - &Self::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) - .map_err(|e| { - log::error!("failed to execute invoke tx: {:?}", e); - Error::::TransactionExecutionFailed - })?; - - let tx_hash = transaction.tx_hash; + let tx_execution_infos = match transaction.tx.version() { + TransactionVersion::ZERO => { + run_non_revertible_transaction(&transaction, &mut state, &block_context, true, charge_fee) + } + _ => run_revertible_transaction(&transaction, &mut state, &block_context, true, charge_fee), + } + .map_err(|e| { + println!("invoke execution failed: {e:?}"); + Error::::TransactionExecutionFailed + })?; + Self::emit_and_store_tx_and_fees_events( - tx_hash, + transaction.tx_hash, &tx_execution_infos.execute_call_info, &tx_execution_infos.fee_transfer_call_info, ); - Self::store_transaction(tx_hash, Transaction::Invoke(input_transaction), tx_execution_infos.revert_error); + Self::store_transaction( + transaction.tx_hash, + Transaction::AccountTransaction(AccountTransaction::Invoke(transaction)), + tx_execution_infos.revert_error, + ); Ok(()) } @@ -528,23 +546,14 @@ pub mod pallet { /// * `DispatchResult` - The result of the transaction. #[pallet::call_index(2)] #[pallet::weight({0})] - pub fn declare( - origin: OriginFor, - transaction: DeclareTransaction, - contract_class: ContractClass, - ) -> DispatchResult { + pub fn declare(origin: OriginFor, transaction: DeclareTransaction) -> DispatchResult { + ensure!(!transaction.only_query(), Error::::QueryTransactionCannotBeExecuted); // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; - let input_transaction = transaction; - let chain_id = Self::chain_id(); - let transaction = input_transaction - .try_into_executable::(chain_id, contract_class.clone(), false) - .map_err(|_| Error::::InvalidContractClassForThisDeclareVersion)?; - // 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 @@ -553,24 +562,25 @@ pub mod pallet { Error::::AccountNotDeployed ); + let mut state = BlockifierStateAdapter::::default(); + let charge_fee = !::DisableTransactionFee::get(); + // Execute - let tx_execution_infos = transaction - .execute( - &mut BlockifierStateAdapter::::default(), - &Self::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) - .map_err(|_| Error::::TransactionExecutionFailed)?; - - let tx_hash = transaction.tx_hash(); + let tx_execution_infos = + run_non_revertible_transaction(&transaction, &mut state, &Self::get_block_context(), true, charge_fee) + .map_err(|e| { + println!("declare failed: {e:?}"); + Error::::TransactionExecutionFailed + })?; + Self::emit_and_store_tx_and_fees_events( - tx_hash, + transaction.tx_hash(), &tx_execution_infos.execute_call_info, &tx_execution_infos.fee_transfer_call_info, ); Self::store_transaction( - tx_hash, - Transaction::Declare(input_transaction, contract_class), + transaction.tx_hash(), + Transaction::AccountTransaction(AccountTransaction::Declare(transaction.clone())), tx_execution_infos.revert_error, ); @@ -592,40 +602,32 @@ pub mod pallet { #[pallet::call_index(3)] #[pallet::weight({0})] pub fn deploy_account(origin: OriginFor, transaction: DeployAccountTransaction) -> DispatchResult { + ensure!(!transaction.only_query, Error::::QueryTransactionCannotBeExecuted); // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; - let input_transaction = transaction; - let chain_id = T::ChainId::get(); - let transaction = input_transaction.into_executable::(chain_id, false); - // Check if contract is deployed ensure!( !ContractClassHashes::::contains_key(transaction.contract_address), Error::::AccountAlreadyDeployed ); + let mut state = BlockifierStateAdapter::::default(); + let charge_fee = !::DisableTransactionFee::get(); + // Execute - let tx_execution_infos = transaction - .execute( - &mut BlockifierStateAdapter::::default(), - &Self::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) - .map_err(|e| { - log::error!("failed to deploy account: {:?}", e); - Error::::TransactionExecutionFailed - })?; - - let tx_hash = transaction.tx_hash; + let tx_execution_infos = + run_non_revertible_transaction(&transaction, &mut state, &Self::get_block_context(), true, charge_fee) + .map_err(|_| Error::::TransactionExecutionFailed)?; + Self::emit_and_store_tx_and_fees_events( - tx_hash, + transaction.tx_hash, &tx_execution_infos.execute_call_info, &tx_execution_infos.fee_transfer_call_info, ); Self::store_transaction( - tx_hash, - Transaction::DeployAccount(input_transaction), + transaction.tx_hash, + Transaction::AccountTransaction(AccountTransaction::DeployAccount(transaction)), tx_execution_infos.revert_error, ); @@ -647,19 +649,11 @@ pub mod pallet { /// * Compute weight #[pallet::call_index(4)] #[pallet::weight({0})] - pub fn consume_l1_message( - origin: OriginFor, - transaction: HandleL1MessageTransaction, - paid_fee_on_l1: Fee, - ) -> DispatchResult { + pub fn consume_l1_message(origin: OriginFor, transaction: L1HandlerTransaction) -> DispatchResult { // This ensures that the function can only be called via unsigned transaction. ensure_none(origin)?; - let input_transaction = transaction; - let chain_id = Self::chain_id(); - let transaction = input_transaction.into_executable::(chain_id, paid_fee_on_l1, false); - - let nonce: Nonce = transaction.tx.nonce; + let nonce = transaction.tx.nonce; // Ensure that L1 Message has not been executed Self::ensure_l1_message_not_executed(&nonce).map_err(|_| Error::::L1MessageAlreadyExecuted)?; @@ -669,27 +663,22 @@ pub mod pallet { // Either successfully or not L1Messages::::mutate(|nonces| nonces.insert(nonce)); + // Init caches + let mut state = BlockifierStateAdapter::::default(); + // Execute - let tx_execution_infos = transaction - .execute( - &mut BlockifierStateAdapter::::default(), - &Self::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) - .map_err(|e| { - log::error!("Failed to consume l1 message: {}", e); - Error::::TransactionExecutionFailed - })?; - - let tx_hash = transaction.tx_hash; + let tx_execution_infos = + execute_l1_handler_transaction(&transaction, &mut state, &Self::get_block_context()) + .map_err(|_| Error::::TransactionExecutionFailed)?; + Self::emit_and_store_tx_and_fees_events( - tx_hash, + transaction.tx_hash, &tx_execution_infos.execute_call_info, &tx_execution_infos.fee_transfer_call_info, ); Self::store_transaction( - tx_hash, - Transaction::L1Handler(input_transaction), + transaction.tx_hash, + Transaction::L1HandlerTransaction(transaction), tx_execution_infos.revert_error, ); @@ -733,9 +722,12 @@ pub mod pallet { let transaction = Self::get_call_transaction(call.clone()).map_err(|_| InvalidTransaction::Call)?; + println!("before validate unsigned tx nonce"); let tx_priority_info = Self::validate_unsigned_tx_nonce(&transaction)?; + println!("before validate unsigned tx"); Self::validate_unsigned_tx(&transaction)?; + println!("after validate unsigned tx"); let mut valid_transaction_builder = ValidTransaction::with_tag_prefix("starknet") .priority(u64::MAX) @@ -746,15 +738,22 @@ pub mod pallet { // Make sure txs from same account are executed in correct order (nonce based ordering) TxPriorityInfo::RegularTxs { sender_address, transaction_nonce, sender_nonce } => { valid_transaction_builder = - valid_transaction_builder.and_provides((sender_address, Felt252Wrapper(transaction_nonce.0))); + valid_transaction_builder.and_provides((sender_address, transaction_nonce)); + println!("tx nonce: {:?}, sender_nonce: {:?}", transaction_nonce, sender_nonce); + + // Future nonces requires the previous one to be execute before if transaction_nonce > sender_nonce { - valid_transaction_builder = valid_transaction_builder - .and_requires((sender_address, Felt252Wrapper(transaction_nonce.0 - FieldElement::ONE))); + valid_transaction_builder = valid_transaction_builder.and_requires(( + sender_address, + Nonce::from(Felt252Wrapper::from( + Felt252Wrapper::from(transaction_nonce).0 - FieldElement::ONE, + )), + )); } } TxPriorityInfo::L1Handler { nonce } => { valid_transaction_builder = - valid_transaction_builder.and_provides((Felt252Wrapper::ZERO, Felt252Wrapper(nonce.0))); + valid_transaction_builder.and_provides((ContractAddress::default(), nonce)); } _ => {} } @@ -789,16 +788,18 @@ impl Pallet { /// # Returns /// /// The transaction - fn get_call_transaction(call: Call) -> Result { + fn get_call_transaction(call: Call) -> Result { let tx = match call { - Call::::invoke { transaction } => UserTransaction::Invoke(transaction).into(), - Call::::declare { transaction, contract_class } => { - UserTransaction::Declare(transaction, contract_class).into() + Call::::invoke { transaction } => { + Transaction::AccountTransaction(AccountTransaction::Invoke(transaction)) + } + Call::::declare { transaction } => { + Transaction::AccountTransaction(AccountTransaction::Declare(transaction)) } - Call::::deploy_account { transaction } => UserTransaction::DeployAccount(transaction).into(), - Call::::consume_l1_message { transaction, paid_fee_on_l1 } => { - UserOrL1HandlerTransaction::L1Handler(transaction, paid_fee_on_l1) + Call::::deploy_account { transaction } => { + Transaction::AccountTransaction(AccountTransaction::DeployAccount(transaction)) } + Call::::consume_l1_message { transaction } => Transaction::L1HandlerTransaction(transaction), _ => return Err(()), }; @@ -812,24 +813,27 @@ impl Pallet { let block_number = UniqueSaturatedInto::::unique_saturated_into(frame_system::Pallet::::block_number()); let block_timestamp = Self::block_timestamp(); - let fee_token_address = Self::fee_token_address(); + let fee_token_addresses = Self::fee_token_addresses(); let sequencer_address = Self::sequencer_address(); - let chain_id = Self::chain_id_str(); - - let vm_resource_fee_cost = Default::default(); - BlockContext { - block_number: BlockNumber(block_number), - block_timestamp: BlockTimestamp(block_timestamp), - chain_id: ChainId(chain_id), - sequencer_address, - fee_token_address, - vm_resource_fee_cost, - invoke_tx_max_n_steps: T::InvokeTxMaxNSteps::get(), - validate_max_n_steps: T::ValidateMaxNSteps::get(), - gas_price: T::L1GasPrice::get().price_in_wei, - max_recursion_depth: T::MaxRecursionDepth::get(), - } + let chain_id = ChainId(Self::chain_id_str()); + let gas_prices = T::L1GasPrices::get(); + + BlockContext::new_unchecked( + &BlockInfo { + block_number: BlockNumber(block_number), + block_timestamp: BlockTimestamp(block_timestamp), + sequencer_address, + gas_prices, + // TODO + // I have no idea what this is, let's say we did not use any for now + use_kzg_da: false, + }, + &ChainInfo { chain_id, fee_token_addresses }, + // TODO + // I'm clueless on what those values should be + VersionedConstants::latest_constants(), + ) } /// convert chain_id @@ -887,7 +891,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, @@ -895,13 +899,18 @@ impl Pallet { storage_address: address, caller_address: ContractAddress::default(), call_type: CallType::Call, - initial_gas: INITIAL_GAS, + initial_gas: VersionedConstants::latest_constants().tx_initial_gas(), }; - let max_n_steps = block_context.invoke_tx_max_n_steps; - let mut resources = ExecutionResources::default(); - let mut entry_point_execution_context = - EntryPointExecutionContext::new(block_context, Default::default(), max_n_steps); + let mut resources = cairo_vm::vm::runners::cairo_runner::ExecutionResources::default(); + let mut entry_point_execution_context = EntryPointExecutionContext::new_invoke( + Arc::new(TransactionContext { + block_context, + tx_info: TransactionInfo::Deprecated(DeprecatedTransactionInfo::default()), + }), + false, + ) + .map_err(|_| Error::::TransactionExecutionFailed)?; match entrypoint.execute( &mut BlockifierStateAdapter::::default(), @@ -951,7 +960,7 @@ impl Pallet { let protocol_version = T::ProtocolVersion::get(); let extra_data = None; - let l1_gas_price = T::L1GasPrice::get(); + let l1_gas_price = T::L1GasPrices::get(); let block = StarknetBlock::new( StarknetHeader::new( @@ -1104,15 +1113,19 @@ impl Pallet { } pub fn config_hash() -> StarkHash { - T::SystemHash::compute_hash_on_elements(&[ + Felt252Wrapper(T::SystemHash::compute_hash_on_elements(&[ FieldElement::from_byte_slice_be(SN_OS_CONFIG_HASH_VERSION.as_bytes()).unwrap(), T::ChainId::get().into(), - Self::fee_token_address().0.0.into(), - ]) + Felt252Wrapper::from(Self::fee_token_addresses().eth_fee_token_address.0.0).0, + ])) .into() } pub fn is_transaction_fee_disabled() -> bool { T::DisableTransactionFee::get() } + + fn init_cached_state() -> CachedState> { + CachedState::new(BlockifierStateAdapter::::default(), GlobalContractCache::new(10)) + } } diff --git a/crates/pallets/starknet/src/simulations.rs b/crates/pallets/starknet/src/simulations.rs index 4b22e7202d..314301c5da 100644 --- a/crates/pallets/starknet/src/simulations.rs +++ b/crates/pallets/starknet/src/simulations.rs @@ -1,25 +1,22 @@ use alloc::vec::Vec; -use blockifier::block_context::BlockContext; -use blockifier::state::cached_state::CommitmentStateDiff; -use blockifier::state::state_api::State; +use blockifier::context::BlockContext; +use blockifier::state::cached_state::{CachedState, CommitmentStateDiff}; +use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::errors::TransactionExecutionError; use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::{ExecutableTransaction, L1HandlerTransaction}; use frame_support::storage; -use mp_felt::Felt252Wrapper; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags, TransactionSimulationResult}; -use mp_transactions::execution::{Execute, ExecutionConfig}; -use mp_transactions::{HandleL1MessageTransaction, UserOrL1HandlerTransaction, UserTransaction}; use sp_core::Get; use sp_runtime::DispatchError; -use starknet_api::transaction::Fee; -use crate::blockifier_state_adapter::{BlockifierStateAdapter, CachedBlockifierStateAdapter}; -use crate::execution_config::RuntimeExecutionConfigBuilder; +use crate::blockifier_state_adapter::BlockifierStateAdapter; use crate::{Config, Error, Pallet}; impl Pallet { - pub fn estimate_fee(transactions: Vec) -> Result, DispatchError> { + pub fn estimate_fee(transactions: Vec) -> Result, DispatchError> { storage::transactional::with_transaction(|| { storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::estimate_fee_inner( transactions, @@ -28,25 +25,27 @@ impl Pallet { .map_err(|_| Error::::FailedToCreateATransactionalStorageExecution)? } - fn estimate_fee_inner(transactions: Vec) -> Result, DispatchError> { + fn estimate_fee_inner(transactions: Vec) -> Result, DispatchError> { let transactions_len = transactions.len(); - let chain_id = Self::chain_id(); let block_context = Self::get_block_context(); - let mut execution_config = RuntimeExecutionConfigBuilder::new::().with_query_mode().build(); + let mut cached_state = Self::init_cached_state(); let fee_res_iterator = transactions .into_iter() .map(|tx| { - execution_config.set_offset_version(tx.offset_version()); - - match Self::execute_user_transaction(tx, chain_id, &block_context, &execution_config) { + match Self::execute_account_transaction( + tx, + &mut cached_state, + &block_context, + &SimulationFlags::default(), + ) { Ok(execution_info) if !execution_info.is_reverted() => Ok(execution_info), Err(e) => { - log::error!("Transaction execution failed during fee estimation: {e}"); + println!("Transaction execution failed during fee estimation: {e}"); Err(Error::::TransactionExecutionFailed) } Ok(execution_info) => { - log::error!( + println!( "Transaction execution reverted during fee estimation: {}", // Safe due to the `match` branch order execution_info.revert_error.unwrap() @@ -57,12 +56,13 @@ impl Pallet { }) .map(|exec_info_res| { exec_info_res.map(|exec_info| { + println!("exec info: {:#?}", exec_info); exec_info .actual_resources .0 .get("l1_gas_usage") .ok_or_else(|| DispatchError::from(Error::::MissingL1GasUsage)) - .map(|l1_gas_usage| (exec_info.actual_fee.0 as u64, *l1_gas_usage)) + .map(|l1_gas_usage| (exec_info.actual_fee.0, *l1_gas_usage)) }) }); @@ -73,8 +73,9 @@ impl Pallet { Ok(fees) } + pub fn simulate_transactions( - transactions: Vec, + transactions: Vec, simulation_flags: &SimulationFlags, ) -> Result, DispatchError> { storage::transactional::with_transaction(|| { @@ -87,20 +88,15 @@ impl Pallet { } fn simulate_transactions_inner( - transactions: Vec, + transactions: Vec, simulation_flags: &SimulationFlags, ) -> Result, DispatchError> { - let chain_id = Self::chain_id(); let block_context = Self::get_block_context(); - let mut execution_config = - RuntimeExecutionConfigBuilder::new::().with_simulation_mode(simulation_flags).build(); let tx_execution_results: Vec<(CommitmentStateDiff, TransactionSimulationResult)> = transactions .into_iter() .map(|tx| { - execution_config.set_offset_version(tx.offset_version()); - - let res = Self::execute_transaction_with_state_diff(tx, chain_id, &block_context, &execution_config); + let res = Self::execute_transaction_with_state_diff(tx, &block_context, simulation_flags); let result = res.0.map_err(|e| { log::error!("Transaction execution failed during simulation: {e}"); PlaceHolderErrorTypeForFailedStarknetExecution @@ -113,7 +109,7 @@ impl Pallet { } pub fn simulate_message( - message: HandleL1MessageTransaction, + message: L1HandlerTransaction, simulation_flags: &SimulationFlags, ) -> Result, DispatchError> { storage::transactional::with_transaction(|| { @@ -126,18 +122,14 @@ impl Pallet { } fn simulate_message_inner( - message: HandleL1MessageTransaction, + message: L1HandlerTransaction, simulation_flags: &SimulationFlags, ) -> Result, DispatchError> { - let chain_id = Self::chain_id(); let block_context = Self::get_block_context(); - let mut execution_config = - RuntimeExecutionConfigBuilder::new::().with_simulation_mode(simulation_flags).build(); + let mut cached_state = Self::init_cached_state(); - // Follow `offset` from Pallet Starknet where it is set to false - execution_config.set_offset_version(false); - let tx_execution_result = - Self::execute_message(message, chain_id, &block_context, &execution_config).map_err(|e| { + let tx_execution_result = Self::execute_message(message, &mut cached_state, &block_context, simulation_flags) + .map_err(|e| { log::error!("Transaction execution failed during simulation: {e}"); PlaceHolderErrorTypeForFailedStarknetExecution }); @@ -145,7 +137,7 @@ impl Pallet { Ok(tx_execution_result) } - pub fn estimate_message_fee(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError> { + pub fn estimate_message_fee(message: L1HandlerTransaction) -> Result<(u128, u128, u128), DispatchError> { storage::transactional::with_transaction(|| { storage::TransactionOutcome::Rollback(Result::<_, DispatchError>::Ok(Self::estimate_message_fee_inner( message, @@ -154,43 +146,37 @@ impl Pallet { .map_err(|_| Error::::FailedToCreateATransactionalStorageExecution)? } - fn estimate_message_fee_inner(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError> { - let chain_id = Self::chain_id(); + fn estimate_message_fee_inner(message: L1HandlerTransaction) -> Result<(u128, u128, u128), DispatchError> { + let mut cached_state = Self::init_cached_state(); - // Follow `offset` from Pallet Starknet where it is set to false - let tx_execution_infos = - match message.into_executable::(chain_id, Fee(u128::MAX), false).execute( - &mut BlockifierStateAdapter::::default(), - &Self::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().with_query_mode().with_disable_nonce_validation().build(), - ) { - Ok(execution_info) if !execution_info.is_reverted() => Ok(execution_info), - Err(e) => { - log::error!( - "Transaction execution failed during fee estimation: {e} {:?}", - std::error::Error::source(&e) - ); - Err(Error::::TransactionExecutionFailed) - } - Ok(execution_info) => { - log::error!( - "Transaction execution reverted during fee estimation: {}", - // Safe due to the `match` branch order - execution_info.revert_error.unwrap() - ); - Err(Error::::TransactionExecutionFailed) - } - }?; + let tx_execution_infos = match message.execute(&mut cached_state, &Self::get_block_context(), true, true) { + Ok(execution_info) if !execution_info.is_reverted() => Ok(execution_info), + Err(e) => { + log::error!( + "Transaction execution failed during fee estimation: {e} {:?}", + std::error::Error::source(&e) + ); + Err(Error::::TransactionExecutionFailed) + } + Ok(execution_info) => { + log::error!( + "Transaction execution reverted during fee estimation: {}", + // Safe due to the `match` branch order + execution_info.revert_error.unwrap() + ); + Err(Error::::TransactionExecutionFailed) + } + }?; if let Some(l1_gas_usage) = tx_execution_infos.actual_resources.0.get("l1_gas_usage") { - Ok((T::L1GasPrice::get().price_in_wei, tx_execution_infos.actual_fee.0 as u64, *l1_gas_usage)) + Ok((T::L1GasPrices::get().eth_l1_gas_price.into(), tx_execution_infos.actual_fee.0 as u128, *l1_gas_usage)) } else { Err(Error::::MissingL1GasUsage.into()) } } pub fn re_execute_transactions( - transactions: Vec, + transactions: Vec, ) -> Result< Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError, @@ -204,56 +190,37 @@ impl Pallet { } fn re_execute_transactions_inner( - transactions: Vec, + transactions: Vec, ) -> Result< Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError, > { - let chain_id = Self::chain_id(); let block_context = Self::get_block_context(); - let execution_config = RuntimeExecutionConfigBuilder::new::().build(); + let mut cached_state = Self::init_cached_state(); let execution_infos = transactions - .iter() + .into_iter() .map(|user_or_l1_tx| { - let mut cached_state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); let res = match user_or_l1_tx { - UserOrL1HandlerTransaction::User(tx) => match tx { - UserTransaction::Declare(tx, contract_class) => tx - .try_into_executable::(chain_id, contract_class.clone(), false) + Transaction::AccountTransaction(tx) => Self::execute_account_transaction( + tx, + &mut cached_state, + &block_context, + &SimulationFlags::default(), + ) + .map_err(|e| { + log::error!("Failed to reexecute a tx: {}", e); + PlaceHolderErrorTypeForFailedStarknetExecution + }), + Transaction::L1HandlerTransaction(tx) => { + Self::execute_message(tx, &mut cached_state, &block_context, &SimulationFlags::default()) .map_err(|e| { log::error!("Failed to reexecute a tx: {}", e); PlaceHolderErrorTypeForFailedStarknetExecution }) - .and_then(|executable| { - executable.execute(&mut cached_state, &block_context, &execution_config).map_err(|e| { - log::error!("Failed to reexecute a tx: {}", e); - PlaceHolderErrorTypeForFailedStarknetExecution - }) - }), - UserTransaction::DeployAccount(tx) => tx - .into_executable::(chain_id, false) - .execute(&mut cached_state, &block_context, &execution_config) - .map_err(|e| { - log::error!("Failed to reexecute a tx: {}", e); - PlaceHolderErrorTypeForFailedStarknetExecution - }), - UserTransaction::Invoke(tx) => tx - .into_executable::(chain_id, false) - .execute(&mut cached_state, &block_context, &execution_config) - .map_err(|e| { - log::error!("Failed to reexecute a tx: {}", e); - PlaceHolderErrorTypeForFailedStarknetExecution - }), - }, - UserOrL1HandlerTransaction::L1Handler(tx, fee) => tx - .into_executable::(chain_id, *fee, false) - .execute(&mut cached_state, &block_context, &execution_config) - .map_err(|e| { - log::error!("Failed to reexecute a tx: {}", e); - PlaceHolderErrorTypeForFailedStarknetExecution - }), + } }; + res.map(|r| (r, cached_state.to_state_diff())) }) .collect(); @@ -261,61 +228,38 @@ impl Pallet { Ok(execution_infos) } - fn execute_user_transaction( - transaction: UserTransaction, - chain_id: Felt252Wrapper, + fn execute_account_transaction( + transaction: AccountTransaction, + state: &mut CachedState>, block_context: &BlockContext, - execution_config: &ExecutionConfig, + simulation_flags: &SimulationFlags, ) -> Result { - match transaction { - UserTransaction::Declare(tx, contract_class) => { - tx.try_into_executable::(chain_id, contract_class.clone(), tx.offset_version()).and_then( - |exec| exec.execute(&mut BlockifierStateAdapter::::default(), block_context, execution_config), - ) - } - UserTransaction::DeployAccount(tx) => { - let executable = tx.into_executable::(chain_id, tx.offset_version()); - executable.execute(&mut BlockifierStateAdapter::::default(), block_context, execution_config) - } - UserTransaction::Invoke(tx) => { - let executable = tx.into_executable::(chain_id, tx.offset_version()); - executable.execute(&mut BlockifierStateAdapter::::default(), block_context, execution_config) - } - } + transaction.execute(state, block_context, simulation_flags.charge_fee, simulation_flags.validate) } fn execute_transaction_with_state_diff( - transaction: UserTransaction, - chain_id: Felt252Wrapper, + transaction: AccountTransaction, block_context: &BlockContext, - execution_config: &ExecutionConfig, + simulation_flags: &SimulationFlags, ) -> (Result, CommitmentStateDiff) { - let mut cached_state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let result = match transaction { - UserTransaction::Declare(tx, contract_class) => tx - .try_into_executable::(chain_id, contract_class.clone(), tx.offset_version()) - .and_then(|exec| exec.execute(&mut cached_state, block_context, execution_config)), - UserTransaction::DeployAccount(tx) => { - let executable = tx.into_executable::(chain_id, tx.offset_version()); - executable.execute(&mut cached_state, block_context, execution_config) - } - UserTransaction::Invoke(tx) => { - let executable = tx.into_executable::(chain_id, tx.offset_version()); - executable.execute(&mut cached_state, block_context, execution_config) - } - }; + let mut cached_state = Self::init_cached_state(); + + let result = transaction.execute( + &mut cached_state, + block_context, + simulation_flags.charge_fee, + simulation_flags.validate, + ); (result, cached_state.to_state_diff()) } fn execute_message( - message: HandleL1MessageTransaction, - chain_id: Felt252Wrapper, + transaction: L1HandlerTransaction, + state: &mut CachedState>, block_context: &BlockContext, - execution_config: &ExecutionConfig, + simulation_flags: &SimulationFlags, ) -> Result { - // Follow `offset` from Pallet Starknet where it is set to false - let executable = message.into_executable::(chain_id, Fee::default(), false); - executable.execute(&mut BlockifierStateAdapter::::default(), block_context, execution_config) + transaction.execute(state, block_context, simulation_flags.charge_fee, simulation_flags.validate) } } 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 6ccd36c700..bca6fc7525 100644 --- a/crates/pallets/starknet/src/tests/block.rs +++ b/crates/pallets/starknet/src/tests/block.rs @@ -1,11 +1,13 @@ -use alloc::sync::Arc; +use std::num::NonZeroU128; +use assert_matches::assert_matches; +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::api_core::{ChainId, ContractAddress, PatriciaKey}; use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ChainId, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use super::mock::default_mock::*; @@ -44,6 +46,7 @@ fn store_block_no_pending_transactions_works() { #[test] fn store_block_with_pending_transactions_works() { new_test_ext::().execute_with(|| { + let chain_id = Starknet::chain_id(); // initialize first block let header = System::finalize(); const BLOCK_NUMBER: u64 = 1; @@ -55,12 +58,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(chain_id, 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(chain_id, Nonce(StarkFelt::ONE)); assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction.into())); @@ -96,26 +99,30 @@ fn get_block_context_works() { let block_context = Starknet::get_block_context(); // correct block_number - assert_eq!(BlockNumber(BLOCK_NUMBER), block_context.block_number); + assert_eq!(BlockNumber(BLOCK_NUMBER), block_context.block_info().block_number); // correct block_timestamp - assert_eq!(BlockTimestamp(0), block_context.block_timestamp); + assert_eq!(BlockTimestamp(0), block_context.block_info().block_timestamp); // correct chain_id - assert_eq!(ChainId(Starknet::chain_id_str()), block_context.chain_id); + assert_eq!(ChainId(Starknet::chain_id_str()), block_context.chain_info().chain_id); // correct sequencer_address - assert_eq!(default_addr, block_context.sequencer_address); + assert_eq!(default_addr, block_context.block_info().sequencer_address); // correct fee_token_address assert_eq!( ContractAddress::try_from(StarkFelt::try_from(FEE_TOKEN_ADDRESS).unwrap()).unwrap(), - block_context.fee_token_address + block_context.chain_info().fee_token_address(&FeeType::Eth) ); - // correct vm_resource_fee_cost - let vm_resoursce_fee_cost: Arc<_> = Default::default(); - assert_eq!(vm_resoursce_fee_cost, block_context.vm_resource_fee_cost); - // correct invoke_tx_max_n_steps: T::InvokeTxMaxNSteps::get(), - assert_eq!(InvokeTxMaxNSteps::get(), block_context.invoke_tx_max_n_steps); - // correct validate_max_n_steps: T::ValidateMaxNSteps::get(), - assert_eq!(ValidateMaxNSteps::get(), block_context.validate_max_n_steps); // correct gas_price, - assert_eq!(10, block_context.gas_price); + assert_matches!( + block_context.block_info().gas_prices, + GasPrices { + eth_l1_gas_price, + strk_l1_gas_price, + eth_l1_data_gas_price, + strk_l1_data_gas_price, + } if eth_l1_gas_price == unsafe { NonZeroU128::new_unchecked(10) } + && strk_l1_gas_price == unsafe { NonZeroU128::new_unchecked(10) } + && eth_l1_data_gas_price == unsafe { NonZeroU128::new_unchecked(10) } + && strk_l1_data_gas_price == unsafe { NonZeroU128::new_unchecked(10) } + ); }); } diff --git a/crates/pallets/starknet/src/tests/build_genesis_config.rs b/crates/pallets/starknet/src/tests/build_genesis_config.rs index ce5733ac3f..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::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 b8f72fa0fd..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::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 95f3ed9140..989deda409 100644 --- a/crates/pallets/starknet/src/tests/constants.rs +++ b/crates/pallets/starknet/src/tests/constants.rs @@ -1,5 +1,6 @@ use lazy_static::lazy_static; -use mp_felt::Felt252Wrapper; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::ContractAddressSalt; pub const ACCOUNT_PRIVATE_KEY: &str = "0x00c1cf1490de1352865301bb8705143f3ef938f97fdf892f1090dcb5ac7bcd1d"; pub const ACCOUNT_PUBLIC_KEY: &str = "0x03603a2692a2ae60abb343e832ee53b55d6b25f02a3ef1565ec691edc7a209b2"; @@ -26,8 +27,12 @@ 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 TEST_ACCOUNT_SALT: Felt252Wrapper = - Felt252Wrapper::from_hex_be("0x0780f72e33c1508df24d8f00a96ecc6e08a850ecb09f7e6dff6a81624c0ef46a").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() + ); } + +pub const TRANSFER_SELECTOR_NAME: &str = "Transfer"; diff --git a/crates/pallets/starknet/src/tests/declare_tx.rs b/crates/pallets/starknet/src/tests/declare_tx.rs index f1fd044921..791835be17 100644 --- a/crates/pallets/starknet/src/tests/declare_tx.rs +++ b/crates/pallets/starknet/src/tests/declare_tx.rs @@ -1,49 +1,83 @@ use assert_matches::assert_matches; +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; -use mp_transactions::{DeclareTransactionV1, DeclareTransactionV2}; use sp_runtime::traits::ValidateUnsigned; use sp_runtime::transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, }; -use starknet_api::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, 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_v1_transaction( + chain_id: Felt252Wrapper, + account_type: AccountType, + sender_address: Option, + signature: Option, + nonce: 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 mut tx = StarknetApiDeclareTransaction::V1(DeclareTransactionV0V1 { + max_fee: Fee(u128::MAX), + signature: Default::default(), + nonce: nonce.unwrap_or_default(), + class_hash: erc20_class_hash, + sender_address, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + // Force to do that because ComputeTransactionHash cannot be implemented on DeclareTransactionV0V1 + // directly... + if let StarknetApiDeclareTransaction::V1(tx) = &mut tx { + tx.signature = signature.unwrap_or_else(|| sign_message_hash(tx_hash)); + } + + BlockifierDeclareTransaction::new(tx, tx_hash, ClassInfo::new(&erc20_class, 0, 1).unwrap()).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 chain_id = Starknet::chain_id(); - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); + let transaction = create_declare_erc20_v1_transaction( + chain_id, + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + None, + ); + let class_hash = transaction.class_hash(); + let contract_class = transaction.contract_class(); - 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, - }; + println!("class_hash to be declared: {:?}", &class_hash); - assert_ok!(Starknet::declare(none_origin.clone(), transaction.clone().into(), erc20_class.clone())); + assert_ok!(Starknet::declare(none_origin.clone(), transaction.clone().into())); + assert_eq!(Starknet::contract_class_by_class_hash(class_hash.0).unwrap(), contract_class); // 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); }); } @@ -53,292 +87,233 @@ fn given_contract_declare_tx_fails_sender_not_deployed() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); + let chain_id = Starknet::chain_id(); // 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, - }; + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd31f").unwrap(), + )); - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::AccountNotDeployed + let transaction = create_declare_erc20_v1_transaction( + chain_id, + AccountType::V0(AccountTypeV0Inner::NoValidate), + Some(contract_address), + None, + None, ); + assert_err!(Starknet::declare(none_origin, transaction), 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() }, - )); - - 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() { +fn given_contract_declare_on_open_zepellin_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::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(_)) + let transaction = create_declare_erc20_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::Openzeppelin), + None, + None, + None, ); + let contract_class = transaction.class_info.contract_class(); + let class_hash = transaction.tx.class_hash(); - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); + assert_ok!(Starknet::declare(RuntimeOrigin::none(), transaction)); + assert_eq!(Starknet::contract_class_by_class_hash(class_hash.0).unwrap(), contract_class); }); } #[test] -fn given_contract_declare_on_braavos_account_then_it_works() { +fn given_contract_declare_on_braavos_types_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_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::Braavos), + None, + None, + None, ); - assert_ok!(validate_result); + let contract_class = transaction.class_info.contract_class(); + let class_hash = transaction.tx.class_hash(); - 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_ok!(Starknet::declare(RuntimeOrigin::none(), transaction)); + assert_eq!(Starknet::contract_class_by_class_hash(class_hash.0).unwrap(), contract_class); }); } - #[test] -fn given_contract_declare_on_braavos_account_with_incorrect_signature_then_it_fails() { +fn given_contract_declare_on_argent_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( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone().into(), contract_class: erc20_class.clone() }, - ), - Err(TransactionValidityError::Invalid(_)) + let transaction = create_declare_erc20_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::Argent), + None, + None, + None, ); + let contract_class = transaction.class_info.contract_class(); + let class_hash = transaction.tx.class_hash(); - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); + assert_ok!(Starknet::declare(RuntimeOrigin::none(), transaction)); + assert_eq!(Starknet::contract_class_by_class_hash(class_hash.0).unwrap(), 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); + for account_type in [AccountTypeV0Inner::Openzeppelin, AccountTypeV0Inner::Argent, AccountTypeV0Inner::Braavos] + { + let transaction = create_declare_erc20_v1_transaction( + Starknet::chain_id(), + AccountType::V0(account_type), + None, + Some(TransactionSignature(vec![StarkFelt::ZERO, StarkFelt::ONE])), + None, + ); + + assert_matches!( + Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::declare { transaction: transaction.clone() }, + ), + Err(TransactionValidityError::Invalid(_)) + ); + + assert_err!( + Starknet::declare(RuntimeOrigin::none(), transaction.into()), + Error::::TransactionExecutionFailed + ); + } }); } #[test] -fn given_contract_declare_on_argent_account_with_incorrect_signature_then_it_fails() { +fn given_contract_declare_on_cairo_1_no_validate_account_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::Argent)); + let account_addr = get_account_address(None, AccountType::V1(AccountTypeV1Inner::NoValidate)); - let erc20_class = get_contract_class("ERC20.json", 0); - let erc20_class_hash = - Felt252Wrapper::from_hex_be("0x057eca87f4b19852cfd4551cf4706ababc6251a8781733a0a11cf8e94211da95").unwrap(); + let hello_starknet_class = get_contract_class("HelloStarknet.casm.json", 1); + let hello_starknet_class_hash = ClassHash( + StarkFelt::try_from("0x05518b17fb5c84683ba37eba8a682b7a6f330911c2216c52c6badff69cc2ec13").unwrap(), + ); + let hello_starknet_compiled_class_hash = CompiledClassHash( + StarkFelt::try_from("0x00df4d3042eec107abe704619f13d92bbe01a58029311b7a1886b23dcbb4ea87").unwrap(), + ); - let transaction = DeclareTransactionV1 { - max_fee: u128::MAX, - signature: vec![Felt252Wrapper::ZERO, Felt252Wrapper::ONE], - nonce: Felt252Wrapper::ZERO, - class_hash: erc20_class_hash, + let mut tx = DeclareTransactionV2 { sender_address: account_addr.into(), - offset_version: false, + class_hash: hello_starknet_class_hash, + compiled_class_hash: hello_starknet_compiled_class_hash, + 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); - assert_matches!( - Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { transaction: transaction.clone().into(), contract_class: erc20_class.clone() }, - ), - Err(TransactionValidityError::Invalid(_)) - ); + let transaction = BlockifierDeclareTransaction::new( + StarknetApiDeclareTransaction::V2(tx), + tx_hash, + ClassInfo::new(&hello_starknet_class, 1, 1).unwrap(), + ) + .unwrap(); - assert_err!( - Starknet::declare(none_origin, transaction.into(), erc20_class), - Error::::TransactionExecutionFailed - ); + 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); }); } #[test] -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 none_origin = RuntimeOrigin::none(); - - 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 mut transaction = 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, - }; - - let chain_id = Starknet::chain_id(); - let transaction_hash = transaction.compute_hash::<::SystemHash>(chain_id, false); - transaction.signature = sign_message_hash(transaction_hash); + let transaction = create_declare_erc20_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + None, + ); - assert_ok!(Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::declare { - transaction: transaction.clone().into(), - contract_class: hello_starknet_class.clone() - }, - )); + let validate_result = + Starknet::validate_unsigned(TransactionSource::InBlock, &crate::Call::declare { transaction }).unwrap(); - 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_eq!(validate_result.longevity, TransactionLongevity::get()); }); } #[test] -fn test_verify_tx_longevity() { +fn test_verify_require_tag_if_tx_nonce_is_one() { 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_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + Some(Nonce(StarkFelt::ONE)), + ); let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, - &crate::Call::declare { transaction, contract_class: erc20_class }, + &crate::Call::declare { transaction: transaction.clone() }, ) .unwrap(); - assert_eq!(validate_result.longevity, TransactionLongevity::get()); + let valid_transaction_expected = ValidTransaction::with_tag_prefix("starknet") + .priority(u64::MAX) + .and_provides((*transaction.tx.sender_address(), *transaction.tx.nonce())) + .longevity(TransactionLongevity::get()) + .propagate(true) + .and_requires(( + *transaction.tx.sender_address(), + Felt252Wrapper::from( + FieldElement::from(Felt252Wrapper::from(transaction.tx.nonce())) - FieldElement::ONE, + ), + )) + .build() + .unwrap(); + + assert_eq!(validate_result, valid_transaction_expected) }); } #[test] -fn test_verify_require_tag() { +fn test_verify_does_not_require_tag_if_tx_nonce_equal_sender_nonce() { 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_v1_transaction( + Starknet::chain_id(), + AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + None, + Some(Nonce(StarkFelt::ZERO)), + ); 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))) .build() .unwrap(); @@ -351,16 +326,17 @@ 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_v1_transaction( Starknet::chain_id(), - Felt252Wrapper::ONE, AccountType::V0(AccountTypeV0Inner::NoValidate), + None, + 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 ad75512bf6..57649ac9dc 100644 --- a/crates/pallets/starknet/src/tests/deploy_account_tx.rs +++ b/crates/pallets/starknet/src/tests/deploy_account_tx.rs @@ -1,68 +1,103 @@ +use std::sync::Arc; + +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::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, TransactionSignature, +}; use starknet_core::utils::get_selector_from_name; use starknet_crypto::FieldElement; use super::mock::default_mock::*; use super::mock::*; use super::utils::{sign_message_hash, sign_message_hash_braavos}; -use crate::tests::constants::{ACCOUNT_PUBLIC_KEY, SALT}; +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 deploy_tx = helper_create_deploy_account_tx(chain_id, salt, calldata, account_class_hash); + let tx_hash = deploy_tx.tx_hash; + let contract_address = deploy_tx.contract_address; - let chain_id = Starknet::chain_id(); - let tx_hash = deploy_tx.compute_hash::<::SystemHash>(chain_id, false); + set_infinite_tokens::(&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(contract_address), account_class_hash.0); let expected_fee_transfer_event = StarknetEvent { content: EventContent { keys: vec![EventKey( - Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap()).into(), + Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap()).into(), )], data: EventData(vec![ - address.0.0, // From + contract_address.0.0, // From StarkFelt::try_from("0xdead").unwrap(), // To - StarkFelt::try_from("0x18a6").unwrap(), // Amount low + StarkFelt::try_from("0xb64e").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high ]), }, - from_address: Starknet::fee_token_address(), + from_address: Starknet::fee_token_addresses().eth_fee_token_address, }; - let events = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events = Starknet::tx_events(tx_hash); assert_eq!(expected_fee_transfer_event, events.last().unwrap().clone()); }); } @@ -72,23 +107,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 +127,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 +147,16 @@ 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)); - - assert_err!( - Starknet::deploy_account(none_origin, transaction), - Error::::TransactionExecutionFailed + let deploy_tx = get_deploy_account_dummy( + chain_id, + Nonce(StarkFelt::ZERO), + *SALT, + AccountType::V0(AccountTypeV0Inner::Argent), ); + + assert_err!(Starknet::deploy_account(none_origin, deploy_tx), Error::::TransactionExecutionFailed); }); } @@ -143,29 +166,42 @@ 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 mut 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 contract_address = deploy_tx.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(contract_address), account_class_hash.0); }); } @@ -175,21 +211,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 +238,46 @@ 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 mut 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 contract_address = deploy_tx.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::(&contract_address); + set_signer(deploy_tx.contract_address, AccountType::V0(AccountTypeV0Inner::Argent)); + assert_ok!(Starknet::validate_unsigned( + TransactionSource::InBlock, + &crate::Call::deploy_account { transaction: deploy_tx.clone() } + )); 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(contract_address), account_class_hash.0); }); } @@ -233,22 +287,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 +314,45 @@ 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, + let mut calldata = Arc::into_inner(calldata.0).unwrap(); + calldata.push(StarkFelt::ONE); + calldata.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + let calldata = Calldata(Arc::new(calldata)); + + let deploy_tx = { + let mut 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 contract_address = deploy_tx.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::(&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(contract_address), proxy_class_hash.0); }); } @@ -293,46 +362,60 @@ 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, + let mut calldata = Arc::into_inner(calldata.0).unwrap(); + calldata.push(StarkFelt::ONE); + calldata.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + let calldata = Calldata(Arc::new(calldata)); + + let deploy_tx = { + let mut 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 contract_address = deploy_tx.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::(&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(contract_address), proxy_class_hash.0); }); } @@ -342,24 +425,27 @@ 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, + let mut calldata = Arc::into_inner(calldata.0).unwrap(); + calldata.push(StarkFelt::ZERO); + calldata.push(StarkFelt::try_from(ACCOUNT_PUBLIC_KEY).unwrap()); + let calldata = Calldata(Arc::new(calldata)); + + 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 +455,14 @@ 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 transaction = get_deploy_account_dummy( + chain_id, + Nonce(StarkFelt::ZERO), + *SALT, + AccountType::V0(AccountTypeV0Inner::NoValidate), + ); let validate_result = Starknet::validate_unsigned(TransactionSource::InBlock, &crate::Call::deploy_account { transaction }); @@ -398,16 +489,21 @@ 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 transaction = get_deploy_account_dummy( + chain_id, + Nonce(StarkFelt::ZERO), + *SALT, + AccountType::V0(AccountTypeV0Inner::NoValidate), + ); + let contract_address = transaction.contract_address; - 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::(&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 c1656c7e72..18b4bc6df8 100644 --- a/crates/pallets/starknet/src/tests/erc20.rs +++ b/crates/pallets/starknet/src/tests/erc20.rs @@ -1,21 +1,24 @@ +use std::sync::Arc; + use blockifier::execution::contract_class::ContractClass; +use blockifier::transaction::transactions::InvokeTransaction; 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::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; -use crate::tests::utils::{build_transfer_invoke_transaction, get_contract_class}; -use crate::types::BuildTransferInvokeTransaction; -use crate::Config; +use crate::tests::constants::{TOKEN_CONTRACT_CLASS_HASH, TRANSFER_SELECTOR_NAME}; +use crate::tests::utils::{build_transfer_invoke_transaction, get_contract_class, BuildTransferInvokeTransaction}; lazy_static! { static ref ERC20_CONTRACT_CLASS: ContractClass = get_contract_class("ERC20.json", 0); @@ -26,42 +29,41 @@ 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") + let tx = InvokeTransactionV1 { + 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 = tx.compute_hash(chain_id, false); + let transaction = InvokeTransaction { tx: tx.into(), tx_hash, only_query: false }; - assert_ok!(Starknet::invoke(origin.clone(), deploy_transaction.into())); + assert_ok!(Starknet::invoke(origin.clone(), transaction)); - let events: Vec = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events: Vec = Starknet::tx_events(tx_hash); // Expected events: // ERC20 -> Transfer // NoValidateAccount -> ContractDeployed @@ -98,42 +100,41 @@ fn given_erc20_transfer_when_invoke_then_it_works() { .unwrap(), // Salt ]), }, - from_address: sender_account, + from_address: sender_address, }, events[1], ); let expected_fee_transfer_event = StarknetEvent { content: EventContent { keys: vec![EventKey( - Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap()).into(), + 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::try_from("0x0000000000000000000000000000000000000000000000000000000000029c8e").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high ]), }, - from_address: Starknet::fee_token_address(), + from_address: Starknet::fee_token_addresses().eth_fee_token_address, }; // Check fee transfer event pretty_assertions::assert_eq!( expected_fee_transfer_event, events.last().unwrap().clone() ); + let chain_id = Starknet::chain_id(); // 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, + let transfer_transaction = build_transfer_invoke_transaction(chain_id, BuildTransferInvokeTransaction { + 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.tx_hash; // Also asserts that the deployment has been saved. assert_ok!(Starknet::invoke(origin, transfer_transaction)); @@ -174,7 +175,8 @@ fn given_erc20_transfer_when_invoke_then_it_works() { StarkFelt::from(0u128) ); - let events: Vec = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events: Vec = Starknet::tx_events(tx_hash); + println!("eventslen: {} events {:#?}", events.len(), events); // Expected events: (added on top of the past ones) // ERC20 -> Transfer // FeeToken -> Transfer @@ -183,7 +185,7 @@ fn given_erc20_transfer_when_invoke_then_it_works() { let expected_event = StarknetEvent { content: EventContent { keys: vec![EventKey( - StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), + StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), )], data: EventData(vec![ StarkFelt::try_from("0x01a3339ec92ac1061e3e0f8e704106286c642eaf302e94a582e5f95ef5e6b4d0").unwrap(), // From @@ -202,16 +204,16 @@ fn given_erc20_transfer_when_invoke_then_it_works() { let expected_fee_transfer_event = StarknetEvent { content: EventContent { keys: vec![EventKey( - StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), + 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::try_from("0x17c00").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high ]), }, - from_address: Starknet::fee_token_address(), + from_address: Starknet::fee_token_addresses().eth_fee_token_address, }; pretty_assertions::assert_eq!( expected_fee_transfer_event, diff --git a/crates/pallets/starknet/src/tests/events.rs b/crates/pallets/starknet/src/tests/events.rs index eec2a0f1b3..642a13fd6c 100644 --- a/crates/pallets/starknet/src/tests/events.rs +++ b/crates/pallets/starknet/src/tests/events.rs @@ -1,13 +1,16 @@ +use std::sync::Arc; + +use blockifier::transaction::transactions::InvokeTransaction; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::InvokeTransactionV1; -use starknet_api::transaction::TransactionHash; +use starknet_api::core::{ContractAddress, Nonce, PatriciaKey}; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{Calldata, Fee, InvokeTransactionV1, TransactionHash, TransactionSignature}; use starknet_core::utils::get_selector_from_name; use super::constants::{FEE_TOKEN_ADDRESS, MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS}; use super::mock::default_mock::*; use super::mock::*; -use crate::Config; const INNER_EVENT_EMITTING_CONTRACT_ADDRESS: &str = "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02cf"; @@ -16,36 +19,36 @@ const INNER_EVENT_EMITTING_CONTRACT_ADDRESS: &str = fn internal_and_external_events_are_emitted_in_the_right_order() { new_test_ext::().execute_with(|| { basic_test_setup(2); + let chain_id = Starknet::chain_id(); - let emit_contract_address = Felt252Wrapper::from_hex_be(MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap(); - let inner_contract_address = Felt252Wrapper::from_hex_be(INNER_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap(); - let fee_token_address = Felt252Wrapper::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let emit_contract_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap())); + let inner_contract_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(INNER_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap())); + let fee_token_address = ContractAddress(PatriciaKey(StarkFelt::try_from(FEE_TOKEN_ADDRESS).unwrap())); let sender_account = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let emit_selector = Felt252Wrapper::from(get_selector_from_name("emit_sandwich").unwrap()); + let emit_selector: StarkFelt = Felt252Wrapper::from(get_selector_from_name("emit_sandwich").unwrap()).into(); - let emit_event_transaction = InvokeTransactionV1 { - sender_address: sender_account.into(), - calldata: vec![ - emit_contract_address, // Token address + let tx = InvokeTransactionV1 { + sender_address: sender_account, + calldata: Calldata(Arc::new(vec![ + emit_contract_address.0.0, // Token address emit_selector, - Felt252Wrapper::ZERO, // Calldata len - ], - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + StarkFelt::ZERO, // Calldata len + ])), + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), }; + let tx_hash = tx.compute_hash(chain_id, false); + let transaction = InvokeTransaction { tx: tx.into(), tx_hash, only_query: false }; - let none_origin = RuntimeOrigin::none(); - Starknet::invoke(none_origin, emit_event_transaction.clone().into()) + Starknet::invoke(RuntimeOrigin::none(), transaction.clone()) .expect("emit sandwich transaction should not fail"); - let chain_id = Starknet::chain_id(); - let tx_hash = emit_event_transaction.compute_hash::<::SystemHash>(chain_id, false); - let events = Starknet::tx_events(TransactionHash::from(tx_hash)); - let event_emitters: Vec = - events.iter().map(|event| Felt252Wrapper::from(event.from_address)).collect(); + let events = Starknet::tx_events(tx_hash); + let event_emitters: Vec = events.iter().map(|event| event.from_address).collect(); pretty_assertions::assert_eq!( event_emitters, diff --git a/crates/pallets/starknet/src/tests/fees_disabled.rs b/crates/pallets/starknet/src/tests/fees_disabled.rs index b0f134c0a0..ac80cacfa6 100644 --- a/crates/pallets/starknet/src/tests/fees_disabled.rs +++ b/crates/pallets/starknet/src/tests/fees_disabled.rs @@ -1,26 +1,28 @@ use frame_support::assert_ok; use mp_felt::Felt252Wrapper; -use mp_transactions::InvokeTransaction; -use starknet_api::api_core::{ContractAddress, EntryPointSelector, PatriciaKey}; +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::*; #[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(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 +36,13 @@ 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(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 +51,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 { + build_transfer_invoke_transaction( + chain_id, + 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), + }, + ) } fn get_balance_default_mock(account_address: ContractAddress) -> (Felt252Wrapper, Felt252Wrapper) { diff --git a/crates/pallets/starknet/src/tests/invoke_tx.rs b/crates/pallets/starknet/src/tests/invoke_tx.rs index 18500bf4ed..ad9ffc257b 100644 --- a/crates/pallets/starknet/src/tests/invoke_tx.rs +++ b/crates/pallets/starknet/src/tests/invoke_tx.rs @@ -1,21 +1,27 @@ +use std::sync::Arc; + use blockifier::abi::abi_utils::get_storage_var_address; +use blockifier::transaction::transactions::InvokeTransaction; use frame_support::{assert_err, assert_ok}; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{InvokeTransaction, InvokeTransactionV1}; use pretty_assertions::assert_eq; use sp_runtime::traits::ValidateUnsigned; use sp_runtime::transaction_validity::{ InvalidTransaction, TransactionSource, TransactionValidityError, ValidTransaction, }; -use starknet_api::api_core::{ContractAddress, Nonce, 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, TransactionHash, TransactionSignature, +}; use starknet_core::utils::get_selector_from_name; use starknet_crypto::FieldElement; -use super::constants::{BLOCKIFIER_ACCOUNT_ADDRESS, MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS}; +use super::constants::{ + BLOCKIFIER_ACCOUNT_ADDRESS, MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS, TRANSFER_SELECTOR_NAME, +}; use super::mock::default_mock::*; use super::mock::*; use super::utils::sign_message_hash; @@ -23,7 +29,9 @@ use crate::tests::{ get_invoke_argent_dummy, get_invoke_braavos_dummy, get_invoke_dummy, get_invoke_emit_event_dummy, get_invoke_nonce_dummy, get_invoke_openzeppelin_dummy, get_storage_read_write_dummy, set_nonce, }; -use crate::{Call, Config, Error, StorageView}; +use crate::{Call, Error, StorageView}; + +const NONCE_ZERO: Nonce = Nonce(StarkFelt::ZERO); #[test] fn given_hardcoded_contract_run_invoke_tx_fails_sender_not_deployed() { @@ -33,16 +41,13 @@ fn given_hardcoded_contract_run_invoke_tx_fails_sender_not_deployed() { let none_origin = RuntimeOrigin::none(); // Wrong address (not deployed) - let contract_address = - Felt252Wrapper::from_hex_be("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd31f").unwrap(); + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x03e437FB56Bb213f5708Fcd6966502070e276c093ec271aA33433b89E21fd31f").unwrap(), + )); - let transaction = InvokeTransactionV1 { - sender_address: contract_address, - calldata: vec![], - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + let mut transaction = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.sender_address = contract_address; }; assert_err!(Starknet::invoke(none_origin, transaction.into()), Error::::AccountNotDeployed); @@ -54,11 +59,9 @@ fn given_hardcoded_contract_run_invoke_tx_then_it_works() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let none_origin = RuntimeOrigin::none(); - - let transaction: InvokeTransaction = get_invoke_dummy(Felt252Wrapper::ZERO).into(); + let transaction = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); - assert_ok!(Starknet::invoke(none_origin.clone(), transaction)); + assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction)); let pending_txs = Starknet::pending(); pretty_assertions::assert_eq!(pending_txs.len(), 1); @@ -73,17 +76,15 @@ fn given_hardcoded_contract_run_invoke_tx_then_it_works() { assert!(events.into_iter().any(|e| e == StarknetEvent { - from_address: Starknet::fee_token_address(), + from_address: Starknet::fee_token_addresses().eth_fee_token_address, content: EventContent { keys: vec![EventKey( - Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap()).into(), + Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap()).into(), )], data: EventData(vec![ StarkFelt::try_from(BLOCKIFIER_ACCOUNT_ADDRESS).unwrap(), - StarkFelt::try_from("0x000000000000000000000000000000000000000000000000000000000000dead") - .unwrap(), - StarkFelt::try_from("0x00000000000000000000000000000000000000000000000000000000000000d2") - .unwrap(), + StarkFelt::try_from("0xdead").unwrap(), + StarkFelt::try_from("0xce04").unwrap(), StarkFelt::from(0u128), ]), }, @@ -98,11 +99,8 @@ fn given_hardcoded_contract_run_invoke_tx_then_event_is_emitted() { let none_origin = RuntimeOrigin::none(); - let transaction: InvokeTransaction = get_invoke_emit_event_dummy().into(); - - let chain_id = Starknet::chain_id(); - let tx_hash = - transaction.compute_hash::<::SystemHash>(chain_id, false); + let transaction = get_invoke_emit_event_dummy(Starknet::chain_id()); + let tx_hash = transaction.tx_hash; assert_ok!(Starknet::invoke(none_origin, transaction)); @@ -118,20 +116,20 @@ fn given_hardcoded_contract_run_invoke_tx_then_event_is_emitted() { }, }; let expected_fee_transfer_event = StarknetEvent { - from_address: Starknet::fee_token_address(), + from_address: Starknet::fee_token_addresses().eth_fee_token_address, content: EventContent { keys: vec![EventKey( - StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(mp_fee::TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), + StarkFelt::try_from(Felt252Wrapper::from(get_selector_from_name(TRANSFER_SELECTOR_NAME).unwrap())).unwrap(), )], data: EventData(vec![ StarkFelt::try_from("0x01a3339ec92ac1061e3e0f8e704106286c642eaf302e94a582e5f95ef5e6b4d0").unwrap(), // From StarkFelt::try_from("0xdead").unwrap(), // To - StarkFelt::try_from("0xd2").unwrap(), // Amount low + StarkFelt::try_from("0xd156").unwrap(), // Amount low StarkFelt::from(0u128), // Amount high ]), }, }; - let events: Vec = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events: Vec = Starknet::tx_events(tx_hash); // Actual event. pretty_assertions::assert_eq!( @@ -151,64 +149,61 @@ fn given_hardcoded_contract_run_invoke_tx_then_multiple_events_is_emitted() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let emit_contract_address = Felt252Wrapper::from_hex_be(MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap(); + let chain_id = Starknet::chain_id(); + let emit_contract_address = + ContractAddress(PatriciaKey(StarkFelt::try_from(MULTIPLE_EVENT_EMITTING_CONTRACT_ADDRESS).unwrap())); let sender_account = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let emit_internal_selector = Felt252Wrapper::from(get_selector_from_name("emit_internal").unwrap()); - let emit_external_selector = Felt252Wrapper::from(get_selector_from_name("emit_external").unwrap()); + let emit_internal_selector = Felt252Wrapper::from(get_selector_from_name("emit_internal").unwrap()).into(); + let emit_external_selector = Felt252Wrapper::from(get_selector_from_name("emit_external").unwrap()).into(); let expected_emitted_internal_event_hash = get_selector_from_name("internal").unwrap(); let expected_emitted_external_event_hash = get_selector_from_name("external").unwrap(); - let emit_internal_event_transaction = InvokeTransactionV1 { + let emit_internal_event_tx = starknet_api::transaction::InvokeTransactionV1 { sender_address: sender_account.into(), - calldata: vec![ - emit_contract_address, // Token address + calldata: Calldata(Arc::new(vec![ + emit_contract_address.0.0, // Token address emit_internal_selector, - Felt252Wrapper::ZERO, // Calldata len - ], - nonce: Felt252Wrapper::ZERO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + StarkFelt::ZERO, // Calldata len + ])), + nonce: Nonce(StarkFelt::ZERO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), }; let none_origin = RuntimeOrigin::none(); - let chain_id = Starknet::chain_id(); - let tx_hash = - emit_internal_event_transaction.compute_hash::<::SystemHash>(chain_id, false); + let tx_hash = emit_internal_event_tx.compute_hash(chain_id, false); + let transaction = InvokeTransaction { tx: emit_internal_event_tx.into(), tx_hash, only_query: false }; - assert_ok!(Starknet::invoke(none_origin, emit_internal_event_transaction.into())); + assert_ok!(Starknet::invoke(none_origin.clone(), transaction)); - let events: Vec = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events: Vec = Starknet::tx_events(tx_hash); let first_event = events.first(); assert_eq!( first_event.and_then(|e| e.content.keys.get(0).cloned()).unwrap(), EventKey(Felt252Wrapper::from(expected_emitted_internal_event_hash).into()) ); - let do_two_event_transaction = InvokeTransactionV1 { - sender_address: sender_account.into(), - calldata: vec![ - emit_contract_address, // Token address + let do_two_event_tx = starknet_api::transaction::InvokeTransactionV1 { + sender_address: sender_account, + calldata: Calldata(Arc::new(vec![ + emit_contract_address.0.0, // Token address emit_external_selector, - Felt252Wrapper::ZERO, // Calldata len - ], - nonce: Felt252Wrapper::ONE, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + StarkFelt::ZERO, // Calldata len + ])), + nonce: Nonce(StarkFelt::ONE), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), }; + let tx_hash = do_two_event_tx.compute_hash(chain_id, false); + let transaction = InvokeTransaction { tx: do_two_event_tx.into(), tx_hash, only_query: false }; - let none_origin = RuntimeOrigin::none(); - - assert_ok!(Starknet::invoke(none_origin, do_two_event_transaction.clone().into())); + assert_ok!(Starknet::invoke(none_origin, transaction)); - let chain_id = Starknet::chain_id(); - let tx_hash = do_two_event_transaction.compute_hash::<::SystemHash>(chain_id, false); - let events = Starknet::tx_events(TransactionHash::from(tx_hash)); + let events = Starknet::tx_events(tx_hash); assert_eq!( events[0].content.keys[0], EventKey(Felt252Wrapper::from(expected_emitted_external_event_hash).into()) @@ -222,7 +217,7 @@ fn given_hardcoded_contract_run_storage_read_and_write_it_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let transaction = get_storage_read_write_dummy(); + let transaction = get_storage_read_write_dummy(Starknet::chain_id()); let transaction = transaction.into(); @@ -241,13 +236,13 @@ fn test_verify_nonce() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let tx = get_invoke_dummy(Felt252Wrapper::ZERO); + let tx = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); // Test for a valid nonce (0) assert_ok!(Starknet::invoke(RuntimeOrigin::none(), tx.into())); // Test for an invalid nonce (actual: 0, expected: 1) - let tx_2 = get_invoke_dummy(Felt252Wrapper::ZERO); + let tx_2 = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); assert_err!( Starknet::invoke(RuntimeOrigin::none(), tx_2.into()), @@ -262,13 +257,7 @@ fn given_hardcoded_contract_run_invoke_on_openzeppelin_account_then_it_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let transaction: InvokeTransaction = get_invoke_openzeppelin_dummy().into(); - - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::invoke { transaction: transaction.clone() }, - ); - assert_ok!(validate_result); + let transaction = get_invoke_openzeppelin_dummy(Starknet::chain_id()); assert_ok!(Starknet::invoke(none_origin, transaction)); }); @@ -281,9 +270,11 @@ fn given_hardcoded_contract_run_invoke_on_openzeppelin_account_with_incorrect_si let none_origin = RuntimeOrigin::none(); - let mut transaction: InvokeTransactionV1 = get_invoke_openzeppelin_dummy(); + let mut transaction = get_invoke_openzeppelin_dummy(Starknet::chain_id()); // by default we get valid signature so set it to something invalid - transaction.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + }; let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, @@ -305,15 +296,10 @@ fn given_hardcoded_contract_run_invoke_on_argent_account_then_it_works() { let none_origin = RuntimeOrigin::none(); let chain_id = Starknet::chain_id(); - let mut transaction: InvokeTransactionV1 = get_invoke_argent_dummy(); - let tx_hash = transaction.compute_hash::<::SystemHash>(chain_id, false); - transaction.signature = sign_message_hash(tx_hash); - - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::invoke { transaction: transaction.clone().into() }, - ); - assert_ok!(validate_result); + let mut transaction = get_invoke_argent_dummy(chain_id); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; assert_ok!(Starknet::invoke(none_origin, transaction.into())); }); @@ -325,8 +311,10 @@ fn given_hardcoded_contract_run_invoke_on_argent_account_with_incorrect_signatur basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let mut transaction = get_invoke_argent_dummy(); - transaction.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; + let mut transaction = get_invoke_argent_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + }; let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, @@ -347,16 +335,10 @@ fn given_hardcoded_contract_run_invoke_on_braavos_account_then_it_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let chain_id = Starknet::chain_id(); - let mut transaction: InvokeTransactionV1 = get_invoke_braavos_dummy(); - let tx_hash = transaction.compute_hash::<::SystemHash>(chain_id, false); - transaction.signature = sign_message_hash(tx_hash); - - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &crate::Call::invoke { transaction: transaction.clone().into() }, - ); - assert_ok!(validate_result); + let mut transaction = get_invoke_braavos_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; assert_ok!(Starknet::invoke(none_origin, transaction.into())); }); @@ -368,8 +350,10 @@ fn given_hardcoded_contract_run_invoke_on_braavos_account_with_incorrect_signatu basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let mut transaction = get_invoke_braavos_dummy(); - transaction.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; + let mut transaction = get_invoke_braavos_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + }; let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, @@ -391,15 +375,17 @@ fn given_hardcoded_contract_run_invoke_with_inner_call_in_validate_then_it_fails let none_origin = RuntimeOrigin::none(); let sender_address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::InnerCall)); - let mut transaction: InvokeTransactionV1 = get_invoke_dummy(Felt252Wrapper::ZERO); - transaction.signature = vec![Felt252Wrapper::ONE, Felt252Wrapper::ONE]; - transaction.sender_address = sender_address.into(); + let mut transaction = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = TransactionSignature(vec![StarkFelt::ONE, StarkFelt::ONE]); + tx.sender_address = sender_address; + }; - let storage_key = get_storage_var_address("destination", &[]).unwrap(); + let storage_key = get_storage_var_address("destination", &[]); let destination = StarkFelt::try_from(TEST_CONTRACT_ADDRESS).unwrap(); StorageView::::insert((sender_address, storage_key), destination); - let storage_key = get_storage_var_address("function_selector", &[]).unwrap(); + let storage_key = get_storage_var_address("function_selector", &[]); let selector = get_selector_from_name("without_arg").unwrap(); StorageView::::insert( (sender_address, storage_key), @@ -419,15 +405,14 @@ fn given_account_not_deployed_invoke_tx_validate_works_for_nonce_one() { basic_test_setup(2); // Wrong address (not deployed) - let contract_address = Felt252Wrapper::from_hex_be("0x13123131").unwrap(); + let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap())); - let transaction = InvokeTransactionV1 { + let transaction = starknet_api::transaction::InvokeTransactionV1 { sender_address: contract_address, - calldata: vec![], - nonce: Felt252Wrapper::ONE, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + calldata: Calldata::default(), + nonce: Nonce(StarkFelt::ONE), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), }; assert_ok!(Starknet::validate_unsigned( @@ -443,15 +428,14 @@ fn given_account_not_deployed_invoke_tx_fails_for_nonce_not_one() { basic_test_setup(2); // Wrong address (not deployed) - let contract_address = Felt252Wrapper::from_hex_be("0x13123131").unwrap(); + let contract_address = ContractAddress(PatriciaKey(StarkFelt::try_from("0x13123131").unwrap())); - let transaction = InvokeTransactionV1 { + let transaction = starknet_api::transaction::InvokeTransactionV1 { sender_address: contract_address, - calldata: vec![], - nonce: Felt252Wrapper::TWO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + calldata: Calldata::default(), + nonce: Nonce(StarkFelt::TWO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature::default(), }; assert_eq!( @@ -469,7 +453,7 @@ fn test_verify_tx_longevity() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = get_invoke_dummy(Felt252Wrapper::ZERO); + let transaction = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, @@ -485,7 +469,7 @@ fn test_verify_require_tag() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = get_invoke_nonce_dummy(); + let transaction = get_invoke_nonce_dummy(Starknet::chain_id()); let validate_result = Starknet::validate_unsigned( TransactionSource::InBlock, @@ -494,10 +478,13 @@ fn test_verify_require_tag() { 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(), + Nonce::from(Felt252Wrapper::from(Felt252Wrapper::from(transaction.tx.nonce()).0 - FieldElement::ONE)), + )) .build(); assert_eq!(validate_result.unwrap(), valid_transaction_expected.unwrap()) @@ -509,9 +496,9 @@ fn test_verify_nonce_in_unsigned_tx() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = get_invoke_dummy(Felt252Wrapper::ZERO); + let transaction = get_invoke_dummy(Starknet::chain_id(), NONCE_ZERO); - let tx_sender = transaction.sender_address.into(); + let tx_sender = transaction.tx.sender_address(); let tx_source = TransactionSource::InBlock; let call = Call::invoke { transaction: transaction.into() }; diff --git a/crates/pallets/starknet/src/tests/l1_handler_validation.rs b/crates/pallets/starknet/src/tests/l1_handler_validation.rs index 75f692eca5..61033a1649 100644 --- a/crates/pallets/starknet/src/tests/l1_handler_validation.rs +++ b/crates/pallets/starknet/src/tests/l1_handler_validation.rs @@ -1,16 +1,32 @@ use assert_matches::assert_matches; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::L1HandlerTransaction as BlockifierL1HandlerTransaction; use mp_felt::Felt252Wrapper; -use mp_transactions::{HandleL1MessageTransaction, UserOrL1HandlerTransaction}; +use mp_transactions::compute_hash::ComputeTransactionHash; use sp_runtime::transaction_validity::InvalidTransaction; -use starknet_api::api_core::Nonce; +use starknet_api::core::{ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::Fee; +use starknet_api::transaction::{Fee, L1HandlerTransaction as StarknetApiL1HandlerTransaction, TransactionVersion}; use super::mock::default_mock::*; use super::mock::*; use crate::transaction_validation::TxPriorityInfo; use crate::L1Messages; +fn create_l1_handler_transaction(chain_id: Felt252Wrapper, nonce: Nonce) -> Transaction { + let tx = StarknetApiL1HandlerTransaction { + nonce: Nonce(StarkFelt::ONE), + contract_address: ContractAddress(PatriciaKey(Default::default())), + entry_point_selector: Default::default(), + calldata: Default::default(), + version: TransactionVersion(StarkFelt::ZERO), + }; + + let tx_hash = tx.compute_hash(chain_id, false); + + Transaction::L1HandlerTransaction(BlockifierL1HandlerTransaction { tx, tx_hash, paid_fee_on_l1: Fee(100) }) +} + #[test] fn should_ensure_l1_message_not_executed_work_properly() { new_test_ext::().execute_with(|| { @@ -31,20 +47,9 @@ fn should_accept_unused_nonce() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let nonce: u64 = 1; - let transaction = HandleL1MessageTransaction { - nonce, - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; - - let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); - - assert_eq!( - Starknet::validate_unsigned_tx_nonce(&tx), - Ok(TxPriorityInfo::L1Handler { nonce: Felt252Wrapper::ONE }) - ); + let nonce = Nonce(StarkFelt::ONE); + let tx = create_l1_handler_transaction(Starknet::chain_id(), nonce); + assert_eq!(Starknet::validate_unsigned_tx_nonce(&tx), Ok(TxPriorityInfo::L1Handler { nonce })); }); } @@ -53,37 +58,11 @@ fn should_reject_used_nonce() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let nonce: u64 = 1; - let transaction = HandleL1MessageTransaction { - nonce, - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; + let nonce = Nonce(StarkFelt::ONE); + let tx = create_l1_handler_transaction(Starknet::chain_id(), nonce); - let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); - - L1Messages::::mutate(|nonces| nonces.insert(Nonce(nonce.into()))); + L1Messages::::mutate(|nonces| nonces.insert(nonce.into())); assert_matches!(Starknet::validate_unsigned_tx_nonce(&tx), Err(InvalidTransaction::Stale)); }); } - -#[test] -fn should_accept_valid_unsigned_l1_message_tx() { - new_test_ext::().execute_with(|| { - basic_test_setup(2); - - let nonce: u64 = 1; - let transaction = HandleL1MessageTransaction { - nonce, - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; - - let tx = UserOrL1HandlerTransaction::L1Handler(transaction, Fee(100)); - - assert!(Starknet::validate_unsigned_tx(&tx).is_ok()); - }); -} diff --git a/crates/pallets/starknet/src/tests/l1_message.rs b/crates/pallets/starknet/src/tests/l1_message.rs index d44ef90a18..6b6d34dc40 100644 --- a/crates/pallets/starknet/src/tests/l1_message.rs +++ b/crates/pallets/starknet/src/tests/l1_message.rs @@ -1,37 +1,62 @@ +use std::sync::Arc; + use frame_support::{assert_err, assert_ok}; use mp_felt::Felt252Wrapper; -use mp_transactions::HandleL1MessageTransaction; +use mp_transactions::compute_hash::ComputeTransactionHash; use sp_runtime::traits::ValidateUnsigned; use sp_runtime::transaction_validity::{TransactionSource, TransactionValidityError}; -use starknet_api::api_core::{ContractAddress, Nonce, PatriciaKey}; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; -use starknet_api::transaction::Fee; +use starknet_api::transaction::{Calldata, Fee, TransactionVersion}; use super::mock::default_mock::*; use super::mock::*; +use crate::tests::mock::setup_mock::fees_disabled_mock::TransactionLongevity; use crate::{Call, Error, InvalidTransaction, L1Messages}; +fn create_handle_l1_message_transaction( + chain_id: Felt252Wrapper, + nonce: Nonce, + paid_fee_on_l1: Fee, +) -> blockifier::transaction::transactions::L1HandlerTransaction { + let contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), + )); + let from_address = + ContractAddress(PatriciaKey(StarkFelt::try_from("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap())); + + let tx = starknet_api::transaction::L1HandlerTransaction { + nonce, + contract_address, + entry_point_selector: EntryPointSelector( + // test_l1_handler_store_under_caller_address + StarkFelt::try_from("0x014093c40d95d0a3641c087f7d48d55160e1a58bc7c07b0d2323efeeb3087269").unwrap(), + ), + calldata: Calldata(Arc::new(vec![ + from_address.0.0, + StarkFelt::ONE, // value + ])), + version: TransactionVersion(StarkFelt::ZERO), + }; + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::L1HandlerTransaction { tx, tx_hash, paid_fee_on_l1 } +} + #[test] fn verify_tx_validity() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let transaction = HandleL1MessageTransaction { - nonce: Default::default(), - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; + let transaction = create_handle_l1_message_transaction(Starknet::chain_id(), Nonce::default(), Fee(1)); let expected_priority = u64::MAX; let expected_longetivity = TransactionLongevity::get(); let expected_propagate = true; - let validate_result = Starknet::validate_unsigned( - TransactionSource::InBlock, - &Call::consume_l1_message { transaction, paid_fee_on_l1: Fee(100) }, - ); + let validate_result = + Starknet::validate_unsigned(TransactionSource::InBlock, &Call::consume_l1_message { transaction }); assert!(validate_result.is_ok()); let validate_result = validate_result.unwrap(); @@ -43,25 +68,19 @@ fn verify_tx_validity() { } #[test] -fn should_reject_used_nonce() { +fn validate_should_reject_used_nonce() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let nonce: u64 = 1; - - let transaction = HandleL1MessageTransaction { - nonce, - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; + let nonce = Nonce(StarkFelt::ONE); + let transaction = create_handle_l1_message_transaction(Starknet::chain_id(), nonce, Fee(1)); let tx_source = TransactionSource::InBlock; - let call = Call::consume_l1_message { transaction, paid_fee_on_l1: Fee(100) }; + let call = Call::consume_l1_message { transaction }; assert!(Starknet::validate_unsigned(tx_source, &call).is_ok()); - L1Messages::::mutate(|nonces| nonces.insert(Nonce(StarkFelt::from(nonce)))); + L1Messages::::mutate(|nonces| nonces.insert(nonce)); assert_eq!( Starknet::validate_unsigned(tx_source, &call), @@ -71,90 +90,48 @@ fn should_reject_used_nonce() { } #[test] -fn should_reject_zero_fee() { +fn work() { + // Execute `test_l1_handler_store_under_caller_address()` new_test_ext::().execute_with(|| { basic_test_setup(2); - let nonce: u64 = 1; + let transaction = create_handle_l1_message_transaction(Starknet::chain_id(), Nonce(StarkFelt::ONE), Fee(1)); - let transaction = HandleL1MessageTransaction { - nonce, - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: Default::default(), - }; - - let tx_source = TransactionSource::InBlock; - let call = Call::consume_l1_message { transaction, paid_fee_on_l1: Fee(0) }; - - assert_eq!( - Starknet::validate_unsigned(tx_source, &call), - Err(TransactionValidityError::Invalid(InvalidTransaction::Payment)) - ); - }); -} + assert_ok!(Starknet::consume_l1_message(RuntimeOrigin::none(), transaction.clone())); -#[test] -fn work() { - // Execute `test_l1_handler_store_under_caller_address()` - new_test_ext::().execute_with(|| { - basic_test_setup(2); - let contract_address = - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(); - let from_address = Felt252Wrapper::from_hex_be("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); - - let transaction = HandleL1MessageTransaction { - nonce: 1, - contract_address, - entry_point_selector: Felt252Wrapper::from_hex_be( - "0x014093c40d95d0a3641c087f7d48d55160e1a58bc7c07b0d2323efeeb3087269", // test_l1_handler_store_under_caller_address - ) - .unwrap(), - calldata: vec![ - from_address, - Felt252Wrapper::from_hex_be("0x1").unwrap(), // value - ], - }; - assert_ok!(Starknet::consume_l1_message(RuntimeOrigin::none(), transaction, Fee(1))); - - let storage_key = ( - ContractAddress(PatriciaKey(StarkFelt::from(contract_address))), - StorageKey(PatriciaKey(StarkFelt::from(from_address))), - ); + let contract_address = transaction.tx.contract_address; + let from_address = transaction.tx.calldata.0.first().unwrap(); + let storage_key = (contract_address, StorageKey(PatriciaKey(*from_address))); assert_eq!(Starknet::storage(storage_key), StarkFelt::from(1u128)); }); } #[test] -fn fail_if_no_fee() { +fn fail_if_no_fee_paid() { // Execute `test_l1_handler_store_under_caller_address()` new_test_ext::().execute_with(|| { basic_test_setup(2); - let contract_address = - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(); - let from_address = Felt252Wrapper::from_hex_be("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); - - let transaction = HandleL1MessageTransaction { - nonce: 1, - contract_address, - entry_point_selector: Felt252Wrapper::from_hex_be( - "0x014093c40d95d0a3641c087f7d48d55160e1a58bc7c07b0d2323efeeb3087269", - ) - .unwrap(), - calldata: vec![ - from_address, - Felt252Wrapper::from_hex_be("0x1").unwrap(), // value - ], - }; + + let transaction = create_handle_l1_message_transaction(Starknet::chain_id(), Nonce(StarkFelt::ONE), Fee(0)); + + // Validate fails + assert_eq!( + Starknet::validate_unsigned( + TransactionSource::InBlock, + &Call::consume_l1_message { transaction: transaction.clone() } + ), + Err(TransactionValidityError::Invalid(InvalidTransaction::Payment)) + ); + // Execution fails assert_err!( - Starknet::consume_l1_message(RuntimeOrigin::none(), transaction, Fee(0)), + Starknet::consume_l1_message(RuntimeOrigin::none(), transaction.clone()), Error::::TransactionExecutionFailed ); - let storage_key = ( - ContractAddress(PatriciaKey(StarkFelt::from(contract_address))), - StorageKey(PatriciaKey(StarkFelt::from(from_address))), - ); + // Storage unaltered + let contract_address = transaction.tx.contract_address; + let from_address = transaction.tx.calldata.0.first().unwrap(); + let storage_key = (contract_address, StorageKey(PatriciaKey(*from_address))); assert_eq!(Starknet::storage(storage_key), StarkFelt::from(0u128)); }); } diff --git a/crates/pallets/starknet/src/tests/mock/genesis.json b/crates/pallets/starknet/src/tests/mock/genesis.json index e1f6e61a45..55b06bdce8 100644 --- a/crates/pallets/starknet/src/tests/mock/genesis.json +++ b/crates/pallets/starknet/src/tests/mock/genesis.json @@ -296,5 +296,6 @@ "0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02cf" ] ], - "fee_token_address": "0x00000000000000000000000000000000000000000000000000000000000000AA" + "eth_fee_token_address": "0x00000000000000000000000000000000000000000000000000000000000000AA", + "strk_fee_token_address": "0x00000000000000000000000000000000000000000000000000000000000000BB" } diff --git a/crates/pallets/starknet/src/tests/mock/helpers.rs b/crates/pallets/starknet/src/tests/mock/helpers.rs index e336f1a67d..07064c7deb 100644 --- a/crates/pallets/starknet/src/tests/mock/helpers.rs +++ b/crates/pallets/starknet/src/tests/mock/helpers.rs @@ -1,12 +1,11 @@ use alloc::sync::Arc; use mp_felt::Felt252Wrapper; -use mp_transactions::DeployAccountTransaction; use sp_core::H256; -use starknet_api::api_core::{ClassHash, ContractAddress, PatriciaKey}; +use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; -use starknet_api::transaction::Calldata; +use starknet_api::transaction::{Calldata, ContractAddressSalt}; use starknet_core::utils::get_storage_var_address; use starknet_crypto::FieldElement; @@ -35,7 +34,7 @@ pub enum AccountType { V1(AccountTypeV1Inner), } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum AccountTypeV0Inner { Argent, Openzeppelin, @@ -93,16 +92,12 @@ pub fn get_account_calldata(account_type: AccountType) -> Vec<&'static str> { } /// Returns the account address for an account type -pub fn get_account_address(salt: Option, account_type: AccountType) -> ContractAddress { - let class_hash: Felt252Wrapper = get_account_class_hash(account_type).into(); - let calldata: Vec<_> = - get_account_calldata(account_type).into_iter().map(|v| FieldElement::from_hex_be(v).unwrap()).collect(); +pub fn get_account_address(salt: Option, account_type: AccountType) -> ContractAddress { + let class_hash = get_account_class_hash(account_type); + let calldata = Calldata(Arc::new( + get_account_calldata(account_type).into_iter().map(|v| StarkFelt::try_from(v).unwrap()).collect(), + )); let contract_address_salt = salt.unwrap_or(*TEST_ACCOUNT_SALT); - Felt252Wrapper(DeployAccountTransaction::calculate_contract_address( - contract_address_salt.0, - class_hash.0, - &calldata, - )) - .into() + calculate_contract_address(contract_address_salt, class_hash, &calldata, Default::default()).unwrap() } diff --git a/crates/pallets/starknet/src/tests/mock/setup_mock.rs b/crates/pallets/starknet/src/tests/mock/setup_mock.rs index de65a56d4d..4ba04373eb 100644 --- a/crates/pallets/starknet/src/tests/mock/setup_mock.rs +++ b/crates/pallets/starknet/src/tests/mock/setup_mock.rs @@ -16,9 +16,10 @@ macro_rules! mock_runtime { use frame_support::traits::Hooks; use mp_sequencer_address::DEFAULT_SEQUENCER_ADDRESS; use mp_felt::Felt252Wrapper; - use starknet_api::api_core::{PatriciaKey, ContractAddress}; + use starknet_api::core::{PatriciaKey, ContractAddress}; use starknet_api::hash::StarkFelt; - use mp_fee::ResourcePrice; + use blockifier::blockifier::block::GasPrices; + use core::num::NonZeroU128; type Block = frame_system::mocking::MockBlock; @@ -75,7 +76,7 @@ macro_rules! mock_runtime { pub const ChainId: Felt252Wrapper = mp_chain_id::SN_GOERLI_CHAIN_ID; pub const MaxRecursionDepth: u32 = 50; pub const ProgramHash: Felt252Wrapper = mp_program_hash::SN_OS_PROGRAM_HASH; - pub const L1GasPrice: ResourcePrice = ResourcePrice { price_in_strk: None, price_in_wei: 10 }; + pub const L1GasPrices: GasPrices = GasPrices { eth_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, eth_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) } }; } impl pallet_starknet::Config for MockRuntime { @@ -91,7 +92,7 @@ macro_rules! mock_runtime { type ChainId = ChainId; type MaxRecursionDepth = MaxRecursionDepth; type ProgramHash = ProgramHash; - type L1GasPrice = L1GasPrice; + type L1GasPrices = L1GasPrices; } /// Run to block n. diff --git a/crates/pallets/starknet/src/tests/mod.rs b/crates/pallets/starknet/src/tests/mod.rs index 7402b89c18..436dbcefd7 100644 --- a/crates/pallets/starknet/src/tests/mod.rs +++ b/crates/pallets/starknet/src/tests/mod.rs @@ -1,13 +1,20 @@ -use blockifier::abi::abi_utils::get_erc20_balance_var_addresses; +use std::sync::Arc; + +use blockifier::abi::abi_utils::get_fee_token_var_address; +use blockifier::abi::sierra_types::next_storage_key; +use blockifier::execution::contract_class::ClassInfo; use blockifier::state::state_api::State; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{DeclareTransaction, DeclareTransactionV1, DeployAccountTransaction, InvokeTransactionV1}; -use starknet_api::api_core::{ContractAddress, Nonce}; +use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, DeclareTransactionV0V1, DeployAccountTransactionV1, Fee, TransactionSignature, +}; -use self::mock::default_mock::{MockRuntime, Starknet}; +use self::mock::default_mock::Starknet; use self::mock::{get_account_address, AccountType}; +use self::utils::get_contract_class; use crate::blockifier_state_adapter::BlockifierStateAdapter; use crate::tests::mock::account_helper; use crate::tests::utils::sign_message_hash; @@ -24,7 +31,8 @@ mod fees_disabled; mod invoke_tx; mod l1_handler_validation; mod l1_message; -mod no_nonce_validation; +// Disabled because the basic blockifer options don't allow for it +// mod no_nonce_validation; mod query_tx; mod re_execute_transactions; mod send_message; @@ -35,142 +43,218 @@ 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( + chain_id: Felt252Wrapper, + nonce: Nonce, +) -> blockifier::transaction::transactions::InvokeTransaction { + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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![], +fn get_invoke_argent_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + let sender_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x02e63de215f650e9d7e2313c6e9ed26b4f920606fb08576b1663c21a7c4a28c5").unwrap(), + )); + let nonce = Nonce(StarkFelt::ZERO); + let signature = TransactionSignature::default(); + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, nonce, sender_address, calldata, - offset_version: false, - } + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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 } +fn get_invoke_braavos_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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 } +fn get_invoke_emit_event_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + 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 */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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 } +fn get_invoke_nonce_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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 } +fn get_storage_read_write_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + let signature = TransactionSignature::default(); + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } // 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 } +fn get_invoke_openzeppelin_dummy(chain_id: Felt252Wrapper) -> blockifier::transaction::transactions::InvokeTransaction { + 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] */ + ])); + + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: MAX_FEE, + signature, + nonce, + sender_address, + calldata, + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } } /// Returns a dummy declare transaction for the given account type. @@ -178,58 +262,78 @@ fn get_invoke_openzeppelin_dummy() -> InvokeTransactionV1 { /// with starkli. pub fn get_declare_dummy( chain_id: Felt252Wrapper, - nonce: Felt252Wrapper, + nonce: Nonce, account_type: AccountType, -) -> DeclareTransaction { +) -> blockifier::transaction::transactions::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 erc20_class = get_contract_class("ERC20.json", 0); - let mut tx = DeclareTransactionV1 { - max_fee: u64::MAX as u128, - signature: vec![], + let mut tx = starknet_api::transaction::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 tx_hash = tx.compute_hash(chain_id, false); let signature = sign_message_hash(tx_hash); - tx.signature = signature; - tx.into() + if let starknet_api::transaction::DeclareTransaction::V1(tx) = &mut tx { + tx.signature = signature; + } + + let class_info = ClassInfo::new(&erc20_class, 0, 1).unwrap(); + + blockifier::transaction::transactions::DeclareTransaction::new(tx, tx_hash, class_info).unwrap() } /// Returns a dummy deploy account transaction for the given salt and account type pub fn get_deploy_account_dummy( - nonce: Felt252Wrapper, - salt: Felt252Wrapper, + chain_id: Felt252Wrapper, + nonce: Nonce, + contract_address_salt: ContractAddressSalt, account_type: AccountType, -) -> DeployAccountTransaction { +) -> blockifier::transaction::transactions::DeployAccountTransaction { let (account_class_hash, calldata) = account_helper(account_type); - DeployAccountTransaction { - max_fee: u64::MAX as u128, - signature: vec![], + let tx = starknet_api::transaction::DeployAccountTransaction::V1(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, + }); + 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(); + + blockifier::transaction::transactions::DeployAccountTransaction { tx, tx_hash, contract_address, only_query: false } } /// Sets the balance of the given address to infinite. pub fn set_infinite_tokens(contract_address: &ContractAddress) { - let fee_token_address = Starknet::fee_token_address(); - let (low_key, high_key) = get_erc20_balance_var_addresses(contract_address).unwrap(); + let fee_token_addresses = Starknet::fee_token_addresses(); + let balance_key_low = get_fee_token_var_address(*contract_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_address, low_key, StarkFelt::from(u64::MAX as u128)); - state_adapter.set_storage_at(fee_token_address, high_key, StarkFelt::from(u64::MAX as u128)); + state_adapter + .set_storage_at(fee_token_addresses.eth_fee_token_address, balance_key_low, StarkFelt::from(u64::MAX as u128)) + .unwrap(); + state_adapter + .set_storage_at(fee_token_addresses.eth_fee_token_address, balance_key_high, StarkFelt::from(u64::MAX as u128)) + .unwrap(); } /// Sets nonce for the given address. diff --git a/crates/pallets/starknet/src/tests/no_nonce_validation.rs b/crates/pallets/starknet/src/tests/no_nonce_validation.rs index 52284fcb60..f9c9e24e8a 100644 --- a/crates/pallets/starknet/src/tests/no_nonce_validation.rs +++ b/crates/pallets/starknet/src/tests/no_nonce_validation.rs @@ -1,6 +1,5 @@ use frame_support::assert_ok; -use mp_felt::Felt252Wrapper; -use starknet_api::api_core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::core::Nonce; use starknet_api::hash::StarkFelt; use super::mock::{new_test_ext, no_nonce_validation_mock}; @@ -17,14 +16,14 @@ fn given_invoke_tx_with_invalid_nonce_then_it_does_nothing() { let none_origin = RuntimeOrigin::none(); - let transaction = get_invoke_dummy(Felt252Wrapper::MAX); - let sender_address = transaction.sender_address; + let transaction = get_invoke_dummy(Starknet::chain_id(), Nonce(StarkFelt::THREE)); + let sender_address = transaction.tx.sender_address(); assert_ok!(Starknet::invoke(none_origin, transaction.into())); // check nonce is still 0 - let nonce = Starknet::nonce(ContractAddress::from(sender_address)); - assert_eq!(nonce, Nonce(StarkFelt::from(0u128))); + let nonce = Starknet::nonce(sender_address); + assert_eq!(nonce, Nonce(StarkFelt::ZERO)); }); } @@ -34,19 +33,21 @@ fn given_declare_tx_with_invalid_nonce_then_it_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let chain_id = Starknet::chain_id(); - let transaction = - get_declare_dummy(chain_id, Felt252Wrapper::MAX, AccountType::V0(AccountTypeV0Inner::Openzeppelin)); - let erc20_class_hash = *transaction.class_hash(); - let sender_address = *transaction.sender_address(); + let transaction = get_declare_dummy( + Starknet::chain_id(), + Nonce(StarkFelt::THREE), + AccountType::V0(AccountTypeV0Inner::Openzeppelin), + ); + let erc20_class_hash = transaction.class_hash(); + let sender_address = transaction.tx.sender_address(); let contract_class = get_contract_class("ERC20.json", 0); - assert_ok!(Starknet::declare(none_origin, transaction.clone(), contract_class.clone())); - assert_eq!(Starknet::contract_class_by_class_hash(ClassHash::from(erc20_class_hash)).unwrap(), contract_class); + assert_ok!(Starknet::declare(none_origin, transaction.clone())); + assert_eq!(Starknet::contract_class_by_class_hash(erc20_class_hash.0).unwrap(), contract_class); // check nonce is still 0 - let nonce = Starknet::nonce(ContractAddress::from(sender_address)); + let nonce = Starknet::nonce(sender_address); assert_eq!(nonce, Nonce(StarkFelt::from(0u128))); }); } @@ -57,15 +58,19 @@ fn given_deploy_account_tx_with_invalid_nonce_then_it_works() { basic_test_setup(2); let none_origin = RuntimeOrigin::none(); - let transaction = - get_deploy_account_dummy(Felt252Wrapper::MAX, *SALT, AccountType::V0(AccountTypeV0Inner::NoValidate)); - let account_class_hash = transaction.class_hash; + let transaction = get_deploy_account_dummy( + Starknet::chain_id(), + Nonce(StarkFelt::THREE), + *SALT, + AccountType::V0(AccountTypeV0Inner::NoValidate), + ); + let account_class_hash = transaction.tx.class_hash(); let address = get_account_address(Some(*SALT), AccountType::V0(AccountTypeV0Inner::NoValidate)); set_infinite_tokens::(&address); assert_ok!(Starknet::deploy_account(none_origin, transaction)); - assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash.into()); + assert_eq!(Starknet::contract_class_hash_by_address(address), account_class_hash.0); // check nonce is still 0 let nonce = Starknet::nonce(address); diff --git a/crates/pallets/starknet/src/tests/query_tx.rs b/crates/pallets/starknet/src/tests/query_tx.rs index e3b6bc1278..91015b65ed 100644 --- a/crates/pallets/starknet/src/tests/query_tx.rs +++ b/crates/pallets/starknet/src/tests/query_tx.rs @@ -1,24 +1,26 @@ +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 starknet_api::core::Nonce; +use starknet_api::hash::StarkFelt; use super::mock::default_mock::*; use super::mock::new_test_ext; use crate::tests::utils::sign_message_hash; use crate::tests::{get_invoke_argent_dummy, get_invoke_dummy, get_storage_read_write_dummy}; -use crate::{Config, Error}; +use crate::Error; #[test] 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 chain_id = Starknet::chain_id(); + let tx_1 = get_storage_read_write_dummy(chain_id); + let tx_1 = AccountTransaction::Invoke(tx_1); - let tx_2 = get_invoke_dummy(Felt252Wrapper::ONE); - let tx_2 = UserTransaction::Invoke(tx_2.into()); + let tx_2 = get_invoke_dummy(chain_id, Nonce(StarkFelt::ONE)); + let tx_2 = AccountTransaction::Invoke(tx_2); let txs = vec![tx_1, tx_2]; @@ -26,11 +28,11 @@ fn estimates_tx_fee_successfully_no_validate() { let (actual, l1_gas_usage) = fees[0]; assert!(actual > 0, "actual fee is missing"); - assert!(l1_gas_usage > 0, "this should be charged l1_gas as it store a value to storage"); + assert!(l1_gas_usage > 0, "l1 fee is missing"); let (actual, l1_gas_usage) = fees[1]; assert!(actual > 0, "actual fee is missing"); - assert!(l1_gas_usage == 0, "this should not be charged any l1_gas as it does not store nor send messages"); + assert!(l1_gas_usage > 0, "l1 fee is missing"); }); } @@ -39,9 +41,9 @@ fn estimates_tx_fee_with_query_version() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let tx = get_invoke_dummy(Felt252Wrapper::ZERO); + let transaction = get_invoke_dummy(Starknet::chain_id(), Nonce(StarkFelt::ZERO)); let pre_storage = Starknet::pending().len(); - let tx = UserTransaction::Invoke(tx.into()); + let tx = AccountTransaction::Invoke(transaction.into()); let tx_vec = vec![tx]; @@ -52,22 +54,22 @@ fn estimates_tx_fee_with_query_version() { } #[test] -fn executable_tx_should_not_be_estimable() { +fn executable_tx_should_be_estimable_and_executable() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let chain_id = Starknet::chain_id(); - let mut tx = get_invoke_argent_dummy(); - let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, false); - tx.signature = sign_message_hash(tx_hash); + let mut transaction = get_invoke_argent_dummy(Starknet::chain_id()); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; - let tx_vec = vec![UserTransaction::Invoke(tx.clone().into())]; + let tx_vec = vec![AccountTransaction::Invoke(transaction.clone().into())]; // it should be valid for estimate calls assert_ok!(Starknet::estimate_fee(tx_vec)); // it should be executable - assert_ok!(Starknet::invoke(RuntimeOrigin::none(), tx.clone().into())); + assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction.clone().into())); }); } @@ -76,21 +78,22 @@ fn query_tx_should_not_be_executable() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let chain_id = Starknet::chain_id(); - let mut tx = get_invoke_argent_dummy(); - tx.offset_version = true; - let tx_hash = tx.compute_hash::<::SystemHash>(chain_id, true); - tx.signature = sign_message_hash(tx_hash); + let mut transaction = get_invoke_argent_dummy(Starknet::chain_id()); + transaction.only_query = true; + transaction.tx_hash = transaction.tx.compute_hash(Starknet::chain_id(), true); + if let starknet_api::transaction::InvokeTransaction::V1(tx) = &mut transaction.tx { + tx.signature = sign_message_hash(transaction.tx_hash); + }; - let tx_vec = vec![UserTransaction::Invoke(tx.clone().into())]; + let tx_vec = vec![AccountTransaction::Invoke(transaction.clone().into())]; // it should be valid for estimate calls assert_ok!(Starknet::estimate_fee(tx_vec)); // it should not be executable assert_err!( - Starknet::invoke(RuntimeOrigin::none(), tx.clone().into()), - Error::::TransactionExecutionFailed + Starknet::invoke(RuntimeOrigin::none(), transaction.clone().into()), + Error::::QueryTransactionCannotBeExecuted ); }); } diff --git a/crates/pallets/starknet/src/tests/re_execute_transactions.rs b/crates/pallets/starknet/src/tests/re_execute_transactions.rs index 364b91c5ae..b9660f07c4 100644 --- a/crates/pallets/starknet/src/tests/re_execute_transactions.rs +++ b/crates/pallets/starknet/src/tests/re_execute_transactions.rs @@ -1,87 +1,101 @@ -use blockifier::state::state_api::State; +use std::sync::Arc; + +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::ExecutableTransaction; use mp_felt::Felt252Wrapper; -use mp_transactions::execution::Execute; -use mp_transactions::{DeployAccountTransaction, HandleL1MessageTransaction, UserOrL1HandlerTransaction}; -use starknet_api::api_core::{ContractAddress, Nonce}; -use starknet_api::transaction::Fee; +use mp_transactions::compute_hash::ComputeTransactionHash; +use starknet_api::core::{calculate_contract_address, 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::blockifier_state_adapter::{BlockifierStateAdapter, CachedBlockifierStateAdapter}; -use crate::execution_config::RuntimeExecutionConfigBuilder; -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(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 contract_address = ContractAddress(PatriciaKey( + StarkFelt::try_from("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(), + )); + let from_address = StarkFelt::try_from("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); 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 = get_contract_class("ERC20.json", 0); - - let contract_address = - Felt252Wrapper::from_hex_be("0x024d1e355f6b9d27a5a420c8f4b50cea9154a8e34ad30fc39d7c98d3c177d0d7").unwrap(); - let from_address = Felt252Wrapper::from_hex_be("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045").unwrap(); + get_declare_dummy(chain_id, Nonce(StarkFelt::ZERO), AccountType::V0(AccountTypeV0Inner::Openzeppelin)); // 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(chain_id, false); + blockifier::transaction::transactions::L1HandlerTransaction { tx, tx_hash, paid_fee_on_l1: Fee(10) } }; let txs = vec![ - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Invoke( - get_invoke_dummy(Felt252Wrapper::ZERO).into(), - )), - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Invoke( - get_invoke_dummy(Felt252Wrapper::ONE).into(), - )), - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Declare(declare_tx, erc20_class)), - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::DeployAccount(deploy_tx)), - UserOrL1HandlerTransaction::L1Handler(handle_l1_tx, Fee(10)), + Transaction::AccountTransaction(AccountTransaction::Invoke(get_invoke_dummy( + chain_id, + Nonce(StarkFelt::ZERO), + ))), + Transaction::AccountTransaction(AccountTransaction::Invoke(get_invoke_dummy( + chain_id, + Nonce(StarkFelt::ONE), + ))), + Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx.clone())), + Transaction::AccountTransaction(AccountTransaction::DeployAccount(deploy_tx)), + Transaction::L1HandlerTransaction(handle_l1_tx), ]; // Call the function we want to test @@ -89,21 +103,16 @@ 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(declare_tx.tx.class_hash().0), None); // All txs are there assert_eq!(res.len(), 5); // Now let's check the TransactionInfos returned + let mut state = Starknet::init_cached_state(); let first_invoke_tx_info = match txs.get(0).unwrap() { - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Invoke(invoke_tx)) => { - let mut state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let tx_info = invoke_tx - .into_executable::<::SystemHash>(chain_id, false) - .execute( - &mut state, - &Starknet::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) + Transaction::AccountTransaction(AccountTransaction::Invoke(invoke_tx)) => { + let tx_info = AccountTransaction::Invoke(invoke_tx.clone()) + .execute(&mut state, &Starknet::get_block_context(), true, true) .unwrap(); (tx_info, state.to_state_diff()) } @@ -111,15 +120,9 @@ fn re_execute_tx_ok() { }; assert_eq!(res[0], first_invoke_tx_info); let second_invoke_tx_info = match txs.get(1).unwrap() { - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Invoke(invoke_tx)) => { - let mut state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let tx_info = invoke_tx - .into_executable::<::SystemHash>(chain_id, false) - .execute( - &mut state, - &Starknet::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) + Transaction::AccountTransaction(AccountTransaction::Invoke(invoke_tx)) => { + let tx_info = AccountTransaction::Invoke(invoke_tx.clone()) + .execute(&mut state, &Starknet::get_block_context(), true, true) .unwrap(); (tx_info, state.to_state_diff()) } @@ -127,16 +130,9 @@ fn re_execute_tx_ok() { }; assert_eq!(res[1], second_invoke_tx_info); let declare_tx_info = match txs.get(2).unwrap() { - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::Declare(declare_tx, cc)) => { - let mut state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let tx_info = declare_tx - .try_into_executable::<::SystemHash>(chain_id, cc.clone(), false) - .unwrap() - .execute( - &mut state, - &Starknet::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) + Transaction::AccountTransaction(AccountTransaction::Declare(declare_tx)) => { + let tx_info = AccountTransaction::Declare(declare_tx.clone()) + .execute(&mut state, &Starknet::get_block_context(), true, true) .unwrap(); (tx_info, state.to_state_diff()) } @@ -144,15 +140,9 @@ fn re_execute_tx_ok() { }; assert_eq!(res[2], declare_tx_info); let deploy_account_tx_info = match txs.get(3).unwrap() { - UserOrL1HandlerTransaction::User(mp_transactions::UserTransaction::DeployAccount(deploy_account_tx)) => { - let mut state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let tx_info = deploy_account_tx - .into_executable::<::SystemHash>(chain_id, false) - .execute( - &mut state, - &Starknet::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) + Transaction::AccountTransaction(AccountTransaction::DeployAccount(deploy_account_tx)) => { + let tx_info = AccountTransaction::DeployAccount(deploy_account_tx.clone()) + .execute(&mut state, &Starknet::get_block_context(), true, true) .unwrap(); (tx_info, state.to_state_diff()) } @@ -160,16 +150,8 @@ fn re_execute_tx_ok() { }; assert_eq!(res[3], deploy_account_tx_info); let handle_l1_message_tx_info = match txs.get(4).unwrap() { - UserOrL1HandlerTransaction::L1Handler(l1_tx, fee) => { - let mut state = CachedBlockifierStateAdapter(BlockifierStateAdapter::::default()); - let tx_info = l1_tx - .into_executable::<::SystemHash>(chain_id, *fee, false) - .execute( - &mut state, - &Starknet::get_block_context(), - &RuntimeExecutionConfigBuilder::new::().build(), - ) - .unwrap(); + Transaction::L1HandlerTransaction(l1_tx) => { + let tx_info = l1_tx.clone().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/send_message.rs b/crates/pallets/starknet/src/tests/send_message.rs index d028a03cba..26cc5aefa9 100644 --- a/crates/pallets/starknet/src/tests/send_message.rs +++ b/crates/pallets/starknet/src/tests/send_message.rs @@ -1,14 +1,20 @@ +use std::sync::Arc; + +use blockifier::execution::contract_class::ClassInfo; +use blockifier::transaction::transactions::InvokeTransaction; use frame_support::assert_ok; use mp_felt::Felt252Wrapper; use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{DeclareTransactionV1, DeployAccountTransaction, InvokeTransactionV1}; -use starknet_api::api_core::EthAddress; -use starknet_api::transaction::{L2ToL1Payload, MessageToL1, TransactionHash}; +use starknet_api::core::{calculate_contract_address, ClassHash, EthAddress, Nonce}; +use starknet_api::hash::StarkFelt; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, DeclareTransactionV0V1, Fee, InvokeTransactionV1, L2ToL1Payload, MessageToL1, + TransactionHash, TransactionSignature, +}; use super::mock::default_mock::*; use super::mock::*; use super::utils::get_contract_class; -use crate::Config; // NoValidateAccount (Cairo 0) const DEPLOY_CONTRACT_SELECTOR: &str = "0x02730079d734ee55315f4f141eaed376bddd8c2133523d223a344c5604e0f7f8"; @@ -29,65 +35,72 @@ fn messages_to_l1_are_stored() { new_test_ext::().execute_with(|| { basic_test_setup(2); - let sender_address: Felt252Wrapper = - get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)).into(); + let chain_id = Starknet::chain_id(); + let sender_address = get_account_address(None, AccountType::V0(AccountTypeV0Inner::NoValidate)); + let contract_class = get_contract_class("send_message.json", 0); - let class_hash = Felt252Wrapper::from_hex_be(SEND_MESSAGE_CLASS_HASH).unwrap(); + let class_hash = ClassHash(StarkFelt::try_from(SEND_MESSAGE_CLASS_HASH).unwrap()); - let declare_tx = DeclareTransactionV1 { + let declare_tx = starknet_api::transaction::DeclareTransaction::V1(DeclareTransactionV0V1 { sender_address, 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(vec![]), + }); + let tx_hash = declare_tx.compute_hash(chain_id, false); + let declare_tx = blockifier::transaction::transactions::DeclareTransaction::new( + declare_tx, + tx_hash, + ClassInfo::new(&contract_class, 0, 100).unwrap(), + ) + .unwrap(); - assert_ok!(Starknet::declare(RuntimeOrigin::none(), declare_tx.into(), contract_class)); + assert_ok!(Starknet::declare(RuntimeOrigin::none(), declare_tx.into())); - let salt = Felt252Wrapper::ZERO; - let contract_address: Felt252Wrapper = - DeployAccountTransaction::calculate_contract_address(salt.into(), class_hash.into(), &[]).into(); + let salt = ContractAddressSalt(StarkFelt::ZERO); + let contract_address = + calculate_contract_address(salt, class_hash, &Calldata(Default::default()), Default::default()).unwrap(); let deploy_tx = InvokeTransactionV1 { sender_address, - calldata: vec![ - sender_address, - Felt252Wrapper::from_hex_be(DEPLOY_CONTRACT_SELECTOR).unwrap(), - Felt252Wrapper::from(3u128), // Calldata len - class_hash, - salt, - Felt252Wrapper::ZERO, // Constructor calldata len (no explicit constructor declared) - ], - nonce: Felt252Wrapper::ONE, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + calldata: Calldata(Arc::new(vec![ + sender_address.0.0, + StarkFelt::try_from(DEPLOY_CONTRACT_SELECTOR).unwrap(), + StarkFelt::from(3u128), // Calldata len + class_hash.0, + salt.0, + StarkFelt::ZERO, // Constructor calldata len (no explicit constructor declared) + ])), + nonce: Nonce(StarkFelt::ONE), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), }; assert_ok!(Starknet::invoke(RuntimeOrigin::none(), deploy_tx.into())); - let invoke_tx = InvokeTransactionV1 { + let tx = InvokeTransactionV1 { sender_address, - calldata: vec![ - contract_address, - Felt252Wrapper::from_hex_be(SEND_MESSAGE_TO_L1_SELECTOR).unwrap(), - Felt252Wrapper::from(3u128), // Calldata len - Felt252Wrapper::ZERO, // to_address - Felt252Wrapper::ONE, // payload_len - Felt252Wrapper::TWO, // payload - ], - nonce: Felt252Wrapper::TWO, - max_fee: u128::MAX, - signature: vec![], - offset_version: false, + calldata: Calldata(Arc::new(vec![ + contract_address.0.0, + StarkFelt::try_from(SEND_MESSAGE_TO_L1_SELECTOR).unwrap(), + StarkFelt::from(3u128), // Calldata len + StarkFelt::ZERO, // to_address + StarkFelt::ONE, // payload_len + StarkFelt::TWO, // payload + ])), + nonce: Nonce(StarkFelt::TWO), + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), }; - assert_ok!(Starknet::invoke(RuntimeOrigin::none(), invoke_tx.clone().into())); - let chain_id = Starknet::chain_id(); - let tx_hash = invoke_tx.compute_hash::<::SystemHash>(chain_id, false); - let messages = Starknet::tx_messages(TransactionHash::from(tx_hash)); + let tx_hash = tx.compute_hash(chain_id, false); + + let transaction = InvokeTransaction { tx: tx.into(), tx_hash, only_query: false }; + assert_ok!(Starknet::invoke(RuntimeOrigin::none(), transaction)); + + let messages = Starknet::tx_messages(tx_hash); assert_eq!(1, messages.len()); pretty_assertions::assert_eq!( diff --git a/crates/pallets/starknet/src/tests/sequencer_address.rs b/crates/pallets/starknet/src/tests/sequencer_address.rs index 473f56db9f..48dd006c39 100644 --- a/crates/pallets/starknet/src/tests/sequencer_address.rs +++ b/crates/pallets/starknet/src/tests/sequencer_address.rs @@ -1,7 +1,7 @@ use frame_support::assert_ok; use frame_support::traits::Hooks; use mp_sequencer_address::{DEFAULT_SEQUENCER_ADDRESS, SEQ_ADDR_STORAGE_KEY}; -use starknet_api::api_core::{ContractAddress, PatriciaKey}; +use starknet_api::core::{ContractAddress, PatriciaKey}; use starknet_api::hash::StarkFelt; use super::mock::default_mock::*; diff --git a/crates/pallets/starknet/src/tests/utils.rs b/crates/pallets/starknet/src/tests/utils.rs index fca6010c96..5fb2999283 100644 --- a/crates/pallets/starknet/src/tests/utils.rs +++ b/crates/pallets/starknet/src/tests/utils.rs @@ -7,15 +7,14 @@ use blockifier::execution::contract_class::ContractClass; use mp_felt::Felt252Wrapper; use mp_hashers::pedersen::PedersenHasher; use mp_hashers::HasherT; -use mp_transactions::{InvokeTransaction, InvokeTransactionV1}; -use starknet_api::api_core::EntryPointSelector; -use starknet_api::hash::StarkFelt; -use starknet_api::transaction::Calldata; +use mp_transactions::compute_hash::ComputeTransactionHash; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::hash::{StarkFelt, StarkHash}; +use starknet_api::transaction::{Calldata, Fee, 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")); @@ -31,10 +30,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, @@ -44,47 +43,63 @@ 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 { - InvokeTransactionV1 { - max_fee: u128::MAX, - signature: vec![], +pub fn build_transfer_invoke_transaction( + chain_id: Felt252Wrapper, + request: BuildTransferInvokeTransaction, +) -> blockifier::transaction::transactions::InvokeTransaction { + let tx = starknet_api::transaction::InvokeTransaction::V1(starknet_api::transaction::InvokeTransactionV1 { + max_fee: Fee(u128::MAX), + signature: TransactionSignature(vec![]), nonce: request.nonce, sender_address: request.sender_address, - calldata: vec![ - request.token_address, // Token address - Felt252Wrapper::from_hex_be( - "0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", - ) - .unwrap(), /* transfer - * selector */ - Felt252Wrapper::THREE, // Calldata len - request.recipient, // recipient + calldata: Calldata(Arc::new(vec![ + request.token_address.0.0, // Token address + StarkFelt::try_from("0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e").unwrap(), /* transfer + * selector */ + StarkFelt::THREE, // Calldata len + request.recipient.0.0, // recipient request.amount_low, // initial supply low request.amount_high, // initial supply high - ], - offset_version: false, - } - .into() + ])), + }); + + let tx_hash = tx.compute_hash(chain_id, false); + + blockifier::transaction::transactions::InvokeTransaction { tx, tx_hash, only_query: false } +} + +/// 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) { diff --git a/crates/pallets/starknet/src/transaction_validation.rs b/crates/pallets/starknet/src/transaction_validation.rs index d12e92dd6e..0845f5d211 100644 --- a/crates/pallets/starknet/src/transaction_validation.rs +++ b/crates/pallets/starknet/src/transaction_validation.rs @@ -1,5 +1,10 @@ //! Transaction validation logic. -use blockifier::transaction::errors::TransactionExecutionError; +use blockifier::transaction::account_transaction::AccountTransaction; +use blockifier::transaction::errors::{TransactionExecutionError, TransactionPreValidationError}; +use blockifier::transaction::objects::TransactionInfoCreator; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::ValidatableTransaction; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use frame_support::traits::EnsureOrigin; use mp_transactions::execution::Validate; @@ -58,21 +63,45 @@ impl> + From> Ensure #[derive(Debug, PartialEq, Eq)] pub enum TxPriorityInfo { InvokeV0, - L1Handler { nonce: Felt252Wrapper }, - RegularTxs { sender_address: Felt252Wrapper, transaction_nonce: Felt252Wrapper, sender_nonce: Felt252Wrapper }, + L1Handler { nonce: Nonce }, + RegularTxs { sender_address: ContractAddress, transaction_nonce: Nonce, sender_nonce: Nonce }, } impl Pallet { - pub fn validate_unsigned_tx_nonce( - transaction: &UserOrL1HandlerTransaction, - ) -> Result { + pub fn validate_unsigned_tx_nonce(transaction: &Transaction) -> Result { match transaction { - UserOrL1HandlerTransaction::User(tx) => { - let sender_address: ContractAddress = tx.sender_address().into(); - let sender_nonce: Felt252Wrapper = Pallet::::nonce(sender_address).into(); - let transaction_nonce = match tx.nonce() { - Some(n) => *n, - None => return Ok(TxPriorityInfo::InvokeV0), + Transaction::AccountTransaction(tx) => { + let sender_address = match tx { + AccountTransaction::Declare(tx) => match &tx.tx { + starknet_api::transaction::DeclareTransaction::V0(tx) => tx.sender_address, + starknet_api::transaction::DeclareTransaction::V1(tx) => tx.sender_address, + starknet_api::transaction::DeclareTransaction::V2(tx) => tx.sender_address, + starknet_api::transaction::DeclareTransaction::V3(tx) => tx.sender_address, + }, + AccountTransaction::DeployAccount(tx) => tx.contract_address, + AccountTransaction::Invoke(tx) => match &tx.tx { + starknet_api::transaction::InvokeTransaction::V0(tx) => tx.contract_address, + starknet_api::transaction::InvokeTransaction::V1(tx) => tx.sender_address, + starknet_api::transaction::InvokeTransaction::V3(tx) => tx.sender_address, + }, + }; + let sender_nonce = Pallet::::nonce(sender_address); + let transaction_nonce = match tx { + AccountTransaction::Declare(tx) => match &tx.tx { + starknet_api::transaction::DeclareTransaction::V0(tx) => tx.nonce, + starknet_api::transaction::DeclareTransaction::V1(tx) => tx.nonce, + starknet_api::transaction::DeclareTransaction::V2(tx) => tx.nonce, + starknet_api::transaction::DeclareTransaction::V3(tx) => tx.nonce, + }, + AccountTransaction::DeployAccount(tx) => match &tx.tx { + starknet_api::transaction::DeployAccountTransaction::V1(tx) => tx.nonce, + starknet_api::transaction::DeployAccountTransaction::V3(tx) => tx.nonce, + }, + AccountTransaction::Invoke(tx) => match &tx.tx { + starknet_api::transaction::InvokeTransaction::V0(_) => return Ok(TxPriorityInfo::InvokeV0), + starknet_api::transaction::InvokeTransaction::V1(tx) => tx.nonce, + starknet_api::transaction::InvokeTransaction::V3(tx) => tx.nonce, + }, }; // Reject transaction with an already used Nonce @@ -91,47 +120,58 @@ impl Pallet { ); } - Ok(TxPriorityInfo::RegularTxs { sender_address: tx.sender_address(), transaction_nonce, sender_nonce }) + let sender_address = match tx { + AccountTransaction::Declare(tx) => tx.tx.sender_address(), + AccountTransaction::DeployAccount(tx) => tx.contract_address, + AccountTransaction::Invoke(tx) => tx.tx.sender_address(), + }; + + Ok(TxPriorityInfo::RegularTxs { sender_address, transaction_nonce, sender_nonce }) } - UserOrL1HandlerTransaction::L1Handler(tx, _fee) => { - Self::ensure_l1_message_not_executed(&Nonce(StarkFelt::from(tx.nonce)))?; + Transaction::L1HandlerTransaction(tx) => { + Self::ensure_l1_message_not_executed(&tx.tx.nonce)?; - Ok(TxPriorityInfo::L1Handler { nonce: tx.nonce.into() }) + Ok(TxPriorityInfo::L1Handler { nonce: tx.tx.nonce }) } } } - pub fn validate_unsigned_tx(transaction: &UserOrL1HandlerTransaction) -> Result<(), InvalidTransaction> { - let chain_id = Self::chain_id(); - let block_context = Self::get_block_context(); - let mut state: BlockifierStateAdapter = BlockifierStateAdapter::::default(); - let mut execution_resources = ExecutionResources::default(); - let mut initial_gas = blockifier::abi::constants::INITIAL_GAS_COST; - - match transaction { - UserOrL1HandlerTransaction::User(transaction) => { - let validation_result = - match transaction { - // There is no way to validate it before the account is actuallly deployed - UserTransaction::DeployAccount(_) => Ok(None), - UserTransaction::Declare(tx, contract_class) => tx - .try_into_executable::(chain_id, contract_class.clone(), false) - .map_err(|_| InvalidTransaction::BadProof)? - .validate_tx(&mut state, &block_context, &mut execution_resources, &mut initial_gas, false), - UserTransaction::Invoke(tx) => tx - .into_executable::(chain_id, false) - .validate_tx(&mut state, &block_context, &mut execution_resources, &mut initial_gas, false), - }; + pub fn validate_unsigned_tx(transaction: &Transaction) -> Result<(), InvalidTransaction> { + let _call_info = match transaction { + Transaction::AccountTransaction(transaction) => { + let mut state: BlockifierStateAdapter = BlockifierStateAdapter::::default(); + let block_context = Self::get_block_context(); + let mut inital_gas = block_context.versioned_constants().tx_initial_gas(); + let mut resources = ExecutionResources::default(); + + let validation_result = match transaction { + AccountTransaction::Declare(tx) => { + println!("validating declare tx"); + let tx_context = Arc::new(block_context.to_tx_context(tx)); + tx.validate(&mut state, tx_context, &mut resources, &mut inital_gas, true, true, true) + } + AccountTransaction::DeployAccount(_) => return Ok(()), + AccountTransaction::Invoke(tx) => { + let tx_context = Arc::new(block_context.to_tx_context(tx)); + tx.validate(&mut state, tx_context, &mut resources, &mut inital_gas, true, true, true) + } + }; - if let Err(TransactionExecutionError::ValidateTransactionError( - EntryPointExecutionError::PreExecutionError(PreExecutionError::UninitializedStorageAddress( - contract_address, - )), + // handle the case where we the user sent both its deploy and first tx at the same time + // we assume that the deploy tx is also in the pool and will therefore be executed before + // a bit hacky but it is needed in order to be compatible with wallets + if let Err(TransactionExecutionError::TransactionPreValidationError( + TransactionPreValidationError::InvalidNonce { address, account_nonce, incoming_tx_nonce }, )) = validation_result { - let transaction_nonce = transaction.nonce(); - let sender_address = transaction.sender_address(); - if contract_address.0.0 == sender_address.into() && transaction_nonce == Some(&Felt252Wrapper::ONE) + let sender_address = match transaction { + AccountTransaction::Declare(tx) => tx.tx.sender_address(), + AccountTransaction::DeployAccount(tx) => tx.contract_address, + AccountTransaction::Invoke(tx) => tx.tx.sender_address(), + }; + if address == sender_address + && account_nonce == Nonce(StarkFelt::ZERO) + && incoming_tx_nonce == Nonce(StarkFelt::ONE) { Ok(None) } else { @@ -141,9 +181,9 @@ impl Pallet { validation_result } } - UserOrL1HandlerTransaction::L1Handler(_, fee) => { + Transaction::L1HandlerTransaction(tx) => { // The tx will fail if no fee have been paid - if fee.0 == 0 { + if tx.paid_fee_on_l1 == Fee(0) { return Err(InvalidTransaction::Payment); } diff --git a/crates/pallets/starknet/src/types.rs b/crates/pallets/starknet/src/types.rs index 22031c555d..04a180bc2a 100644 --- a/crates/pallets/starknet/src/types.rs +++ b/crates/pallets/starknet/src/types.rs @@ -1,11 +1,13 @@ //! Starknet pallet custom types. +use std::collections::HashMap; + use blockifier::execution::contract_class::ContractClass; use mp_felt::Felt252Wrapper; use sp_core::ConstU32; use sp_std::vec::Vec; -use starknet_api::api_core::{ClassHash, ContractAddress}; +use starknet_api::core::{ClassHash, ContractAddress}; +use starknet_api::hash::StarkHash; use starknet_api::state::StorageKey; -use starknet_api::stdlib::collections::HashMap; use starknet_api::transaction::{Event, Fee, MessageToL1, TransactionHash}; /// Contract Storage Key @@ -19,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)] @@ -33,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/block/Cargo.toml b/crates/primitives/block/Cargo.toml index ae67127919..0952230ff0 100644 --- a/crates/primitives/block/Cargo.toml +++ b/crates/primitives/block/Cargo.toml @@ -12,11 +12,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blockifier = { workspace = true } -mp-fee = { workspace = true, features = [ - "parity-scale-codec", - "serde", - "scale-info", -] } mp-felt = { workspace = true } mp-hashers = { workspace = true } mp-transactions = { workspace = true } @@ -40,11 +35,8 @@ default = ["std"] std = [ "sp-core/std", "mp-felt/std", - "mp-fee/std", "mp-transactions/std", "mp-hashers/std", - "starknet_api/std", - "blockifier/std", "serde/std", # Optionals "parity-scale-codec?/std", @@ -53,14 +45,8 @@ std = [ parity-scale-codec = [ "dep:parity-scale-codec", "mp-felt/parity-scale-codec", - "mp-fee/parity-scale-codec", "mp-transactions/parity-scale-codec", - "starknet_api/parity-scale-codec", - "blockifier/parity-scale-codec", ] scale-info = [ "dep:scale-info", - "mp-felt/scale-info", - "starknet_api/scale-info", - "blockifier/scale-info", ] diff --git a/crates/primitives/block/src/header.rs b/crates/primitives/block/src/header.rs index 8bcf561e07..1bde9f5d10 100644 --- a/crates/primitives/block/src/header.rs +++ b/crates/primitives/block/src/header.rs @@ -1,16 +1,16 @@ -use alloc::sync::Arc; +use core::num::NonZeroU128; -use blockifier::block_context::BlockContext; -use mp_fee::ResourcePrice; +use blockifier::blockifier::block::{BlockInfo, GasPrices}; +use blockifier::context::{BlockContext, ChainInfo, FeeTokenAddresses}; +use blockifier::versioned_constants::VersionedConstants; use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; use sp_core::U256; -use starknet_api::api_core::{ChainId, ContractAddress}; use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ChainId, ContractAddress}; use starknet_api::hash::StarkHash; -use starknet_api::stdlib::collections::HashMap; -#[derive(Clone, Debug, PartialEq, Eq, Default)] +#[derive(Clone, Debug)] #[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))] @@ -30,12 +30,38 @@ pub struct Header { pub event_count: u128, /// The version of the Starknet protocol used when creating this block pub protocol_version: u8, - /// l1 gas price for this block - pub l1_gas_price: ResourcePrice, + /// Gas prices for this block + pub l1_gas_price: GasPrices, /// Extraneous data that might be useful for running transactions pub extra_data: Option, } +impl Default for Header { + fn default() -> Self { + Self { + // Those are fucked-up value + // Mainly usefull for tests or stuffs like this + // Should probably be removed + l1_gas_price: unsafe { + GasPrices { + eth_l1_gas_price: NonZeroU128::new_unchecked(10), + strk_l1_gas_price: NonZeroU128::new_unchecked(10), + eth_l1_data_gas_price: NonZeroU128::new_unchecked(10), + strk_l1_data_gas_price: NonZeroU128::new_unchecked(10), + } + }, + parent_block_hash: Default::default(), + block_number: Default::default(), + sequencer_address: Default::default(), + block_timestamp: Default::default(), + transaction_count: Default::default(), + event_count: Default::default(), + protocol_version: Default::default(), + extra_data: Default::default(), + } + } +} + impl Header { /// Creates a new header. #[allow(clippy::too_many_arguments)] @@ -48,7 +74,7 @@ impl Header { transaction_count: u128, event_count: u128, protocol_version: u8, - l1_gas_price: ResourcePrice, + gas_prices: GasPrices, extra_data: Option, ) -> Self { Self { @@ -59,26 +85,28 @@ impl Header { transaction_count, event_count, protocol_version, - l1_gas_price, + l1_gas_price: gas_prices, extra_data, } } /// Converts to a blockifier BlockContext - pub fn into_block_context(self, fee_token_address: ContractAddress, chain_id: ChainId) -> BlockContext { - BlockContext { - chain_id, - block_number: BlockNumber(self.block_number), - block_timestamp: BlockTimestamp(self.block_timestamp), - sequencer_address: self.sequencer_address, - vm_resource_fee_cost: Arc::new(HashMap::default()), - fee_token_address, - invoke_tx_max_n_steps: 1000000, - validate_max_n_steps: 1000000, - // FIXME: https://github.com/keep-starknet-strange/madara/issues/329 - gas_price: 10, - max_recursion_depth: 50, - } + pub fn into_block_context(self, fee_token_addresses: FeeTokenAddresses, chain_id: ChainId) -> BlockContext { + BlockContext::new_unchecked( + &BlockInfo { + block_number: BlockNumber(self.block_number), + block_timestamp: BlockTimestamp(self.block_timestamp), + sequencer_address: self.sequencer_address, + gas_prices: self.l1_gas_price, + // TODO + // I have no idea what this is, let's say we did not use any for now + use_kzg_da: false, + }, + &ChainInfo { chain_id, fee_token_addresses }, + // TODO + // I'm clueless on what those values should be + VersionedConstants::latest_constants(), + ) } /// Compute the hash of the header. diff --git a/crates/primitives/block/src/lib.rs b/crates/primitives/block/src/lib.rs index 8f4ef1e31a..5e6c9b8f69 100644 --- a/crates/primitives/block/src/lib.rs +++ b/crates/primitives/block/src/lib.rs @@ -6,13 +6,10 @@ pub extern crate alloc; mod header; -use alloc::vec::Vec; - -pub use header::*; +use blockifier::transaction::transaction_execution::Transaction; +pub use header::Header; use mp_felt::Felt252Wrapper; -use mp_hashers::HasherT; -use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::Transaction; +use starknet_api::transaction::TransactionHash; /// Block Transactions pub type BlockTransactions = Vec; @@ -42,7 +39,7 @@ pub enum BlockId { } /// Starknet block definition. -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default)] #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))] pub struct Block { /// The block header. @@ -75,11 +72,15 @@ impl Block { /// Returns an iterator that iterates over all transaction hashes. /// /// Those transactions are computed using the given `chain_id`. - pub fn transactions_hashes( - &self, - chain_id: Felt252Wrapper, - ) -> impl '_ + Iterator { - self.transactions.iter().map(move |tx| tx.compute_hash::(chain_id, false)) + pub fn transactions_hashes(&self) -> impl '_ + Iterator { + self.transactions.iter().map(|tx| match tx { + Transaction::AccountTransaction(ac) => match ac { + blockifier::transaction::account_transaction::AccountTransaction::Declare(tx) => tx.tx_hash, + blockifier::transaction::account_transaction::AccountTransaction::DeployAccount(tx) => tx.tx_hash, + blockifier::transaction::account_transaction::AccountTransaction::Invoke(tx) => tx.tx_hash, + }, + Transaction::L1HandlerTransaction(lhc) => lhc.tx_hash, + }) } } diff --git a/crates/primitives/block/src/tests.rs b/crates/primitives/block/src/tests.rs index 064a65a5dc..fa9bd8cfa5 100644 --- a/crates/primitives/block/src/tests.rs +++ b/crates/primitives/block/src/tests.rs @@ -1,10 +1,11 @@ use core::convert::TryFrom; +use blockifier::context::FeeTokenAddresses; use mp_felt::Felt252Wrapper; use mp_hashers::pedersen::PedersenHasher; use mp_hashers::HasherT; -use starknet_api::api_core::{ChainId, ContractAddress, PatriciaKey}; use starknet_api::block::{BlockNumber, BlockTimestamp}; +use starknet_api::core::{ChainId, ContractAddress, PatriciaKey}; use starknet_api::hash::{StarkFelt, StarkHash}; use crate::Header; @@ -82,14 +83,24 @@ fn test_to_block_context() { // Create a block header. let block_header = Header { block_number: 1, block_timestamp: 1, sequencer_address, ..Default::default() }; // Create a fee token address. - let fee_token_address = ContractAddress(PatriciaKey(StarkFelt::try_from("AA").unwrap())); + let fee_token_addresses = FeeTokenAddresses { + eth_fee_token_address: ContractAddress(PatriciaKey(StarkFelt::try_from("AA").unwrap())), + strk_fee_token_address: ContractAddress(PatriciaKey(StarkFelt::try_from("BB").unwrap())), + }; // Create a chain id. let chain_id = ChainId("0x1".to_string()); // Try to serialize the block header. - let block_context = block_header.into_block_context(fee_token_address, chain_id); + let block_context = block_header.into_block_context(fee_token_addresses.clone(), chain_id); // Check that the block context was serialized correctly. - assert_eq!(block_context.block_number, BlockNumber(1)); - assert_eq!(block_context.block_timestamp, BlockTimestamp(1)); - assert_eq!(block_context.sequencer_address, sequencer_address); - assert_eq!(block_context.fee_token_address, fee_token_address); + assert_eq!(block_context.block_info().block_number, BlockNumber(1)); + assert_eq!(block_context.block_info().block_timestamp, BlockTimestamp(1)); + assert_eq!(block_context.block_info().sequencer_address, sequencer_address); + assert_eq!( + &block_context.chain_info().fee_token_addresses.eth_fee_token_address, + &fee_token_addresses.eth_fee_token_address + ); + assert_eq!( + &block_context.chain_info().fee_token_addresses.strk_fee_token_address, + &fee_token_addresses.strk_fee_token_address + ); } diff --git a/crates/primitives/digest-log/src/lib.rs b/crates/primitives/digest-log/src/lib.rs index 830eb89dcc..5cad183858 100644 --- a/crates/primitives/digest-log/src/lib.rs +++ b/crates/primitives/digest-log/src/lib.rs @@ -31,7 +31,7 @@ pub const MADARA_ENGINE_ID: ConsensusEngineId = [b'm', b'a', b'd', b'a']; /// /// Right now we only expect Madara to log the Starknet block, /// but other usecases may appears later on. -#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)] +#[derive(Debug, Clone, Encode, Decode)] pub enum Log { #[codec(index = 0)] Block(StarknetBlock), diff --git a/crates/primitives/digest-log/src/tests.rs b/crates/primitives/digest-log/src/tests.rs index 717dc4af45..3437abba8d 100644 --- a/crates/primitives/digest-log/src/tests.rs +++ b/crates/primitives/digest-log/src/tests.rs @@ -11,8 +11,6 @@ fn log_is_found() { digest.push(DigestItem::Consensus(MADARA_ENGINE_ID, Log::Block(block.clone()).encode())); assert!(ensure_log(&digest).is_ok()); - assert_eq!(find_log(&digest).unwrap(), Log::Block(block.clone())); - assert_eq!(find_starknet_block(&digest).unwrap(), block); } #[test] diff --git a/crates/primitives/fee/Cargo.toml b/crates/primitives/fee/Cargo.toml index f035912c8d..9d92cc4699 100644 --- a/crates/primitives/fee/Cargo.toml +++ b/crates/primitives/fee/Cargo.toml @@ -12,35 +12,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] blockifier = { workspace = true } -hashbrown = { workspace = true } -mp-felt = { workspace = true } -mp-state = { workspace = true } -phf = { workspace = true } -sp-arithmetic = { workspace = true } -starknet-core = { workspace = true } -starknet_api = { workspace = true } +sp-core = { workspace = true } +frame-support = { workspace = true } -# Optional dependencies -parity-scale-codec = { workspace = true, optional = true } -scale-info = { workspace = true, optional = true } -serde = { workspace = true, optional = true } -serde_with = { workspace = true, optional = true } - -[features] -default = ["std"] -std = [ - "mp-felt/std", - "starknet_api/std", - "blockifier/std", - "serde?/std", - "serde_with?/std", - "parity-scale-codec?/std", - "scale-info?/std", -] -parity-scale-codec = [ - "dep:parity-scale-codec", - "starknet_api/parity-scale-codec", - "mp-felt/parity-scale-codec", -] -serde = ["dep:serde", "dep:serde_with", "mp-felt/serde"] -scale-info = ["dep:scale-info", "starknet_api/scale-info"] diff --git a/crates/primitives/fee/src/lib.rs b/crates/primitives/fee/src/lib.rs index 504ba5d948..5d44ee6544 100644 --- a/crates/primitives/fee/src/lib.rs +++ b/crates/primitives/fee/src/lib.rs @@ -4,247 +4,248 @@ #[doc(hidden)] pub extern crate alloc; -use alloc::vec; -use alloc::vec::Vec; -#[cfg(feature = "std")] -use std::collections::HashMap; - -use blockifier::abi::constants::GAS_USAGE; -use blockifier::block_context::BlockContext; -use blockifier::execution::entry_point::{ - CallEntryPoint, CallInfo, CallType, EntryPointExecutionContext, ExecutionResources, -}; -use blockifier::state::state_api::State; -use blockifier::transaction::errors::TransactionExecutionError; -use blockifier::transaction::objects::{AccountTransactionContext, ResourcesMapping, TransactionExecutionResult}; -use blockifier::transaction::transaction_types::TransactionType; -use blockifier::transaction::transaction_utils::{calculate_l1_gas_usage, calculate_tx_resources}; -#[cfg(not(feature = "std"))] -use hashbrown::HashMap; -use mp_state::StateChanges; -use sp_arithmetic::fixed_point::{FixedPointNumber, FixedU128}; -use sp_arithmetic::traits::Zero; -use starknet_api::api_core::EntryPointSelector; -use starknet_api::calldata; -use starknet_api::deprecated_contract_class::EntryPointType; -use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{Calldata, Fee}; -use starknet_core::types::ResourcePrice as CoreResourcePrice; - -/// Initial gas for a transaction -pub const INITIAL_GAS: u64 = u64::MAX; -/// Number of storage updates for the fee transfer tx. -pub const FEE_TRANSFER_N_STORAGE_CHANGES: u8 = 2; // Sender and sequencer balance update. -/// Number of storage updates to actually charge for the fee transfer tx. -pub const FEE_TRANSFER_N_STORAGE_CHANGES_TO_CHARGE: u8 = FEE_TRANSFER_N_STORAGE_CHANGES - 1; // Exclude the sequencer balance update, since it's charged once throughout the batch. - -pub static VM_RESOURCE_FEE_COSTS: [(&str, FixedU128); 8] = [ - ("n_steps", FixedU128::from_inner(5_000_000_000_000_000)), - ("pedersen_builtin", FixedU128::from_inner(160_000_000_000_000_000)), - ("range_check_builtin", FixedU128::from_inner(80_000_000_000_000_000)), - ("ecdsa_builtin", FixedU128::from_inner(10_240_000_000_000_000_000)), - ("bitwise_builtin", FixedU128::from_inner(320_000_000_000_000_000)), - ("poseidon_builtin", FixedU128::from_inner(160_000_000_000_000_000)), - ("ec_op_builtin", FixedU128::from_inner(5_120_000_000_000_000_000)), - ("keccak_builtin", FixedU128::from_inner(5_120_000_000_000_000_000)), -]; - -pub const TRANSFER_SELECTOR_NAME: &str = "Transfer"; -pub const TRANSFER_SELECTOR_HASH: [u8; 32] = [ - 0, 131, 175, 211, 244, 202, 237, 198, 238, 191, 68, 36, 111, 229, 78, 56, 201, 94, 49, 121, 165, 236, 158, 168, 23, - 64, 236, 165, 180, 130, 209, 46, -]; // starknet_keccak(TRANSFER_SELECTOR_NAME.as_bytes()).to_le_bytes(); - -#[serde_with::serde_as] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, parity_scale_codec::Decode))] -#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ResourcePrice { - /// The price of one unit of the given resource, denominated in fri (10^-18 strk) - pub price_in_strk: Option, - /// The price of one unit of the given resource, denominated in wei - pub price_in_wei: u128, -} - -impl From for CoreResourcePrice { - fn from(item: ResourcePrice) -> Self { - // TODO: when we rebase starknet-rs those field type will be FieldElements - // Get rid of the type conversions - CoreResourcePrice { price_in_strk: item.price_in_strk, price_in_wei: item.price_in_wei as u64 } - } -} - -/// Gets the transaction resources. -pub fn compute_transaction_resources( - state: &S, - execute_call_info: &Option, - validate_call_info: &Option, - execution_resources: &ExecutionResources, - tx_type: TransactionType, - l1_handler_payload_size: Option, -) -> TransactionExecutionResult { - let state_changes_count = state.count_state_changes(); - let non_optional_call_infos: Vec<&CallInfo> = - vec![execute_call_info, validate_call_info].into_iter().flatten().collect(); - - let l1_gas_usage = calculate_l1_gas_usage(&non_optional_call_infos, state_changes_count, l1_handler_payload_size)?; - let actual_resources = calculate_tx_resources(execution_resources, l1_gas_usage, tx_type)?; - - Ok(actual_resources) -} - -/// Charges the fees for a specific execution resources. -pub fn charge_fee( - state: &mut S, - block_context: &BlockContext, - account_tx_context: AccountTransactionContext, - resources: &ResourcesMapping, - disable_transaction_fee: bool, - disable_fee_charge: bool, - is_query: bool, -) -> TransactionExecutionResult<(Fee, Option)> { - // disable_transaction_fee flag implies that transaction fees have - // been disabled and so we return 0 as the fees - if disable_transaction_fee { - return Ok((Fee(0), None)); - } - - let actual_fee = calculate_tx_fee(resources, block_context)?; - - // Fee charging is skipped in the following cases: - // 1) if is_query is true, it's an estimate fee transaction, so we don't charge fees - // 2) The disable_fee_charge flag is set - // in both cases we return the actual fee. - if disable_fee_charge || is_query { - return Ok((actual_fee, None)); - } - - let fee_transfer_call_info = execute_fee_transfer(state, block_context, account_tx_context, actual_fee)?; - - Ok((actual_fee, Some(fee_transfer_call_info))) -} - -/// Executes the fee transfer tx -fn execute_fee_transfer( - state: &mut dyn State, - block_context: &BlockContext, - account_tx_context: AccountTransactionContext, - actual_fee: Fee, -) -> TransactionExecutionResult { - let max_fee = account_tx_context.max_fee; - if actual_fee > max_fee { - return Err(TransactionExecutionError::FeeTransferError { max_fee, actual_fee }); - } - // TODO: This is what's done in the blockifier but this should be improved. - // FIXME: https://github.com/keep-starknet-strange/madara/issues/332 - // The least significant 128 bits of the amount transferred. - let lsb_amount = StarkFelt::from(actual_fee.0); - // The most significant 128 bits of the amount transferred. - let msb_amount = StarkFelt::from(0_u64); - let storage_address = block_context.fee_token_address; - let fee_transfer_call = CallEntryPoint { - class_hash: None, - code_address: None, - entry_point_type: EntryPointType::External, - // The value TRANSFER_SELECTOR_HASH is hardcoded and it's the encoding of the "transfer" selector so it cannot - // fail. - entry_point_selector: EntryPointSelector(StarkFelt::new(TRANSFER_SELECTOR_HASH).unwrap()), - calldata: calldata![ - *block_context.sequencer_address.0.key(), // Recipient. - lsb_amount, - msb_amount - ], - storage_address, - caller_address: account_tx_context.sender_address, - call_type: CallType::Call, - // The fee-token contract is a Cairo 0 contract, hence the initial gas is irrelevant. - initial_gas: INITIAL_GAS, - }; - - let max_steps = block_context.invoke_tx_max_n_steps; - let mut context = EntryPointExecutionContext::new(block_context.clone(), account_tx_context, max_steps); - - Ok(fee_transfer_call.execute(state, &mut ExecutionResources::default(), &mut context)?) -} - -/// Computes the fees from the execution resources. -pub fn calculate_tx_fee(resources: &ResourcesMapping, block_context: &BlockContext) -> TransactionExecutionResult { - let (l1_gas_usage, vm_resources) = extract_l1_gas_and_vm_usage(resources); - let l1_gas_by_vm_usage = calculate_l1_gas_by_vm_usage(block_context, &vm_resources)?; - - let total_l1_gas_usage = FixedU128::checked_from_integer(l1_gas_usage as u128) - .ok_or(TransactionExecutionError::FixedPointConversion)? - + l1_gas_by_vm_usage; - let tx_fee = total_l1_gas_usage - .ceil() - .checked_mul_int(block_context.gas_price) - .ok_or(TransactionExecutionError::FixedPointConversion)?; - - Ok(Fee(tx_fee)) -} - -/// Computes the fees for l1 gas usage and the vm usage from the execution resources. -/// -/// # Arguments -/// -/// * `resources` - Execution resources to compute the fees from. -/// -/// # Returns -/// -/// [usize] - l1 gas usage. -/// [BTreeMap] - vm resources usage. -pub fn extract_l1_gas_and_vm_usage(resources: &ResourcesMapping) -> (usize, ResourcesMapping) { - let mut vm_resource_usage = resources.0.clone(); - let l1_gas_usage = - vm_resource_usage.remove(GAS_USAGE).expect("`ResourcesMapping` does not have the key `l1_gas_usage`."); - - (l1_gas_usage as usize, ResourcesMapping(vm_resource_usage)) -} - -/// Calculates the L1 gas consumed when submitting the underlying Cairo program to SHARP. -/// I.e., returns the heaviest Cairo resource weight (in terms of L1 gas), as the size of -/// a proof is determined similarly - by the (normalized) largest segment. -pub fn calculate_l1_gas_by_vm_usage( - _block_context: &BlockContext, - vm_resource_usage: &ResourcesMapping, -) -> TransactionExecutionResult { - let vm_resource_fee_costs: HashMap<&str, FixedU128> = HashMap::from(VM_RESOURCE_FEE_COSTS); - // Check if keys in vm_resource_usage are a subset of keys in VM_RESOURCE_FEE_COSTS - if vm_resource_usage.0.keys().any(|key| !vm_resource_fee_costs.contains_key(key.as_str())) { - return Err(TransactionExecutionError::CairoResourcesNotContainedInFeeCosts); - }; - - // Convert Cairo usage to L1 gas usage. - let vm_l1_gas_usage = vm_resource_usage - .0 - .iter() - .map(|(key, &value)| { - let value = ::checked_from_integer(value as u128) - .ok_or(TransactionExecutionError::FixedPointConversion); - - value.map(|v| vm_resource_fee_costs.get(key.as_str()).unwrap().mul(v)) - }) - .try_fold(FixedU128::zero(), |accum, res| res.map(|v| v.max(accum)))?; - - Ok(vm_l1_gas_usage) -} - -#[cfg(test)] -mod vm_resource_fee_costs { - use super::{FixedU128, HashMap, VM_RESOURCE_FEE_COSTS}; - - #[test] - fn check_values_as_floats() { - let hm = HashMap::from(VM_RESOURCE_FEE_COSTS); - - assert_eq!(hm.get("n_steps"), Some(FixedU128::from_float(0.005)).as_ref()); - assert_eq!(hm.get("pedersen_builtin"), Some(FixedU128::from_float(0.16)).as_ref()); - assert_eq!(hm.get("range_check_builtin"), Some(FixedU128::from_float(0.08)).as_ref()); - assert_eq!(hm.get("ecdsa_builtin"), Some(FixedU128::from_float(10.24)).as_ref()); - assert_eq!(hm.get("bitwise_builtin"), Some(FixedU128::from_float(0.32)).as_ref()); - assert_eq!(hm.get("poseidon_builtin"), Some(FixedU128::from_float(0.16)).as_ref()); - assert_eq!(hm.get("ec_op_builtin"), Some(FixedU128::from_float(5.12)).as_ref()); - assert_eq!(hm.get("keccak_builtin"), Some(FixedU128::from_float(5.12)).as_ref()); - } -} +// use alloc::vec; +// use alloc::vec::Vec; +// #[cfg(feature = "std")] +// use std::collections::HashMap; + +// use blockifier::abi::constants::L1_GAS_USAGE; +// use blockifier::context::BlockContext; +// use blockifier::execution::call_info::CallInfo; +// use blockifier::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; +// use blockifier::state::state_api::State; +// use blockifier::transaction::errors::{TransactionExecutionError, TransactionFeeError}; +// use blockifier::transaction::objects::{ResourcesMapping, TransactionExecutionResult}; +// use blockifier::transaction::transaction_types::TransactionType; +// use blockifier::transaction::transaction_utils::calculate_tx_resources; +// use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +// #[cfg(not(feature = "std"))] +// use hashbrown::HashMap; +// use mp_state::StateChanges; +// use sp_arithmetic::fixed_point::{FixedPointNumber, FixedU128}; +// use sp_arithmetic::traits::Zero; +// use starknet_api::calldata; +// use starknet_api::core::EntryPointSelector; +// use starknet_api::deprecated_contract_class::EntryPointType; +// use starknet_api::hash::StarkFelt; +// use starknet_api::transaction::{Calldata, Fee}; +// use starknet_core::types::ResourcePrice as CoreResourcePrice; + +// /// Initial gas for a transaction +// pub const INITIAL_GAS: u64 = u64::MAX; +// /// Number of storage updates for the fee transfer tx. +// pub const FEE_TRANSFER_N_STORAGE_CHANGES: u8 = 2; // Sender and sequencer balance update. +// /// Number of storage updates to actually charge for the fee transfer tx. +// pub const FEE_TRANSFER_N_STORAGE_CHANGES_TO_CHARGE: u8 = FEE_TRANSFER_N_STORAGE_CHANGES - 1; // +// Exclude the sequencer balance update, since it's charged once throughout the batch. + +// pub static VM_RESOURCE_FEE_COSTS: [(&str, FixedU128); 8] = [ +// ("n_steps", FixedU128::from_inner(5_000_000_000_000_000)), +// ("pedersen_builtin", FixedU128::from_inner(160_000_000_000_000_000)), +// ("range_check_builtin", FixedU128::from_inner(80_000_000_000_000_000)), +// ("ecdsa_builtin", FixedU128::from_inner(10_240_000_000_000_000_000)), +// ("bitwise_builtin", FixedU128::from_inner(320_000_000_000_000_000)), +// ("poseidon_builtin", FixedU128::from_inner(160_000_000_000_000_000)), +// ("ec_op_builtin", FixedU128::from_inner(5_120_000_000_000_000_000)), +// ("keccak_builtin", FixedU128::from_inner(5_120_000_000_000_000_000)), +// ]; + +// pub const TRANSFER_SELECTOR_NAME: &str = "Transfer"; +// pub const TRANSFER_SELECTOR_HASH: [u8; 32] = [ +// 0, 131, 175, 211, 244, 202, 237, 198, 238, 191, 68, 36, 111, 229, 78, 56, 201, 94, 49, 121, +// 165, 236, 158, 168, 23, 64, 236, 165, 180, 130, 209, 46, +// ]; // starknet_keccak(TRANSFER_SELECTOR_NAME.as_bytes()).to_le_bytes(); + +// #[serde_with::serde_as] +// #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +// #[cfg_attr(feature = "parity-scale-codec", derive(parity_scale_codec::Encode, +// parity_scale_codec::Decode))] #[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] +// #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +// pub struct ResourcePrice { +// /// The price of one unit of the given resource, denominated in fri (10^-18 strk) +// pub price_in_strk: Option, +// /// The price of one unit of the given resource, denominated in wei +// pub price_in_wei: u128, +// } + +// impl From for CoreResourcePrice { +// fn from(item: ResourcePrice) -> Self { +// // TODO: when we rebase starknet-rs those field type will be FieldElements +// // Get rid of the type conversions +// CoreResourcePrice { price_in_strk: item.price_in_strk, price_in_wei: item.price_in_wei as +// u64 } } +// } + +// /// Gets the transaction resources. +// pub fn compute_transaction_resources( +// state: &S, +// execute_call_info: &Option, +// validate_call_info: &Option, +// execution_resources: &ExecutionResources, +// tx_type: TransactionType, +// l1_handler_payload_size: Option, +// ) -> TransactionExecutionResult { let state_changes_count = +// state.count_state_changes(); let non_optional_call_infos: Vec<&CallInfo> = +// vec![execute_call_info, validate_call_info].into_iter().flatten().collect(); + +// let l1_gas_usage = calculate_l1_gas_usage(&non_optional_call_infos, state_changes_count, +// l1_handler_payload_size)?; let actual_resources = calculate_tx_resources(execution_resources, +// l1_gas_usage, tx_type)?; + +// Ok(actual_resources) +// } + +// /// Charges the fees for a specific execution resources. +// pub fn charge_fee( +// state: &mut S, +// block_context: &BlockContext, +// account_tx_context: AccountTransactionContext, +// resources: &ResourcesMapping, +// disable_transaction_fee: bool, +// disable_fee_charge: bool, +// is_query: bool, +// ) -> TransactionExecutionResult<(Fee, Option)> { // disable_transaction_fee flag +// implies that transaction fees have // been disabled and so we return 0 as the fees if +// disable_transaction_fee { return Ok((Fee(0), None)); } + +// let actual_fee = calculate_tx_fee(resources, block_context)?; + +// // Fee charging is skipped in the following cases: +// // 1) if is_query is true, it's an estimate fee transaction, so we don't charge fees +// // 2) The disable_fee_charge flag is set +// // in both cases we return the actual fee. +// if disable_fee_charge || is_query { +// return Ok((actual_fee, None)); +// } + +// let fee_transfer_call_info = execute_fee_transfer(state, block_context, account_tx_context, +// actual_fee)?; + +// Ok((actual_fee, Some(fee_transfer_call_info))) +// } + +// /// Executes the fee transfer tx +// fn execute_fee_transfer( +// state: &mut dyn State, +// block_context: &BlockContext, +// account_tx_context: AccountTransactionContext, +// actual_fee: Fee, +// ) -> TransactionExecutionResult { +// let max_fee = account_tx_context.max_fee; +// if actual_fee > max_fee { +// return Err(TransactionExecutionError::FeeTransferError { max_fee, actual_fee }); +// } +// // TODO: This is what's done in the blockifier but this should be improved. +// // FIXME: https://github.com/keep-starknet-strange/madara/issues/332 +// // The least significant 128 bits of the amount transferred. +// let lsb_amount = StarkFelt::from(actual_fee.0); +// // The most significant 128 bits of the amount transferred. +// let msb_amount = StarkFelt::from(0_u64); +// let storage_address = block_context.fee_token_address; +// let fee_transfer_call = CallEntryPoint { +// class_hash: None, +// code_address: None, +// entry_point_type: EntryPointType::External, +// // The value TRANSFER_SELECTOR_HASH is hardcoded and it's the encoding of the "transfer" selector so it cannot +// // fail. +// entry_point_selector: EntryPointSelector(StarkFelt::new(TRANSFER_SELECTOR_HASH).unwrap()), +// calldata: calldata![ +// *block_context.sequencer_address.0.key(), // Recipient. +// lsb_amount, +// msb_amount +// ], +// storage_address, +// caller_address: account_tx_context.sender_address, +// call_type: CallType::Call, +// // The fee-token contract is a Cairo 0 contract, hence the initial gas is irrelevant. +// initial_gas: INITIAL_GAS, +// }; + +// let max_steps = block_context.invoke_tx_max_n_steps; +// let mut context = EntryPointExecutionContext::new(block_context.clone(), account_tx_context, +// max_steps); + +// Ok(fee_transfer_call.execute(state, &mut ExecutionResources::default(), &mut context)?) +// } + +// /// Computes the fees from the execution resources. +// pub fn calculate_tx_fee(resources: &ResourcesMapping, block_context: &BlockContext) -> +// TransactionExecutionResult { let (l1_gas_usage, vm_resources) = +// extract_l1_gas_and_vm_usage(resources); let l1_gas_by_vm_usage = +// calculate_l1_gas_by_vm_usage(block_context, &vm_resources)?; + +// let total_l1_gas_usage = FixedU128::checked_from_integer(l1_gas_usage as u128) +// .ok_or(TransactionExecutionError::FixedPointConversion)? +// + l1_gas_by_vm_usage; +// let tx_fee = total_l1_gas_usage +// .ceil() +// .checked_mul_int(block_context.gas_price) +// .ok_or(TransactionExecutionError::FixedPointConversion)?; + +// Ok(Fee(tx_fee)) +// } + +// /// Computes the fees for l1 gas usage and the vm usage from the execution resources. +// /// +// /// # Arguments +// /// +// /// * `resources` - Execution resources to compute the fees from. +// /// +// /// # Returns +// /// +// /// [usize] - l1 gas usage. +// /// [BTreeMap] - vm resources usage. +// pub fn extract_l1_gas_and_vm_usage(resources: &ResourcesMapping) -> (usize, ResourcesMapping) { +// let mut vm_resource_usage = resources.0.clone(); +// let l1_gas_usage = +// vm_resource_usage.remove(L1_GAS_USAGE).expect("`ResourcesMapping` does not have the key +// `l1_gas_usage`."); + +// (l1_gas_usage as usize, ResourcesMapping(vm_resource_usage)) +// } + +// /// Calculates the L1 gas consumed when submitting the underlying Cairo program to SHARP. +// /// I.e., returns the heaviest Cairo resource weight (in terms of L1 gas), as the size of +// /// a proof is determined similarly - by the (normalized) largest segment. +// pub fn calculate_l1_gas_by_vm_usage( +// _block_context: &BlockContext, +// vm_resource_usage: &ResourcesMapping, +// ) -> TransactionExecutionResult { let vm_resource_fee_costs: HashMap<&str, FixedU128> +// = HashMap::from(VM_RESOURCE_FEE_COSTS); // Check if keys in vm_resource_usage are a subset of +// keys in VM_RESOURCE_FEE_COSTS if vm_resource_usage.0.keys().any(|key| +// !vm_resource_fee_costs.contains_key(key.as_str())) { return +// Err(TransactionExecutionError::CairoResourcesNotContainedInFeeCosts); }; + +// // Convert Cairo usage to L1 gas usage. +// let vm_l1_gas_usage = vm_resource_usage +// .0 +// .iter() +// .map(|(key, &value)| { +// let value = ::checked_from_integer(value as u128) +// .ok_or(TransactionFeeError::ExecuteFeeTransferError()); + +// value.map(|v| vm_resource_fee_costs.get(key.as_str()).unwrap().mul(v)) +// }) +// .try_fold(FixedU128::zero(), |accum, res| res.map(|v| v.max(accum)))?; + +// Ok(vm_l1_gas_usage) +// } + +// #[cfg(test)] +// mod vm_resource_fee_costs { +// use super::{FixedU128, HashMap, VM_RESOURCE_FEE_COSTS}; + +// #[test] +// fn check_values_as_floats() { +// let hm = HashMap::from(VM_RESOURCE_FEE_COSTS); + +// assert_eq!(hm.get("n_steps"), Some(FixedU128::from_float(0.005)).as_ref()); +// assert_eq!(hm.get("pedersen_builtin"), Some(FixedU128::from_float(0.16)).as_ref()); +// assert_eq!(hm.get("range_check_builtin"), Some(FixedU128::from_float(0.08)).as_ref()); +// assert_eq!(hm.get("ecdsa_builtin"), Some(FixedU128::from_float(10.24)).as_ref()); +// assert_eq!(hm.get("bitwise_builtin"), Some(FixedU128::from_float(0.32)).as_ref()); +// assert_eq!(hm.get("poseidon_builtin"), Some(FixedU128::from_float(0.16)).as_ref()); +// assert_eq!(hm.get("ec_op_builtin"), Some(FixedU128::from_float(5.12)).as_ref()); +// assert_eq!(hm.get("keccak_builtin"), Some(FixedU128::from_float(5.12)).as_ref()); +// } +// } diff --git a/crates/primitives/felt/Cargo.toml b/crates/primitives/felt/Cargo.toml index 258fe4f90c..d14bfa335e 100644 --- a/crates/primitives/felt/Cargo.toml +++ b/crates/primitives/felt/Cargo.toml @@ -35,7 +35,6 @@ serde = ["dep:serde", "starknet-ff/serde", "dep:serde_with"] std = [ "cairo-vm/std", "thiserror-no-std/std", - "starknet_api/std", "sp-core/std", "starknet-ff/std", "starknet-core/std", diff --git a/crates/primitives/felt/src/starkware_types_conversions.rs b/crates/primitives/felt/src/starkware_types_conversions.rs index 5e8d750ae2..e4087e9afa 100644 --- a/crates/primitives/felt/src/starkware_types_conversions.rs +++ b/crates/primitives/felt/src/starkware_types_conversions.rs @@ -1,5 +1,5 @@ use starknet_api::state::StorageKey; -use starknet_api::{api_core as stcore, block as stb, transaction as sttx}; +use starknet_api::{block as stb, core as stcore, transaction as sttx}; use super::Felt252Wrapper; diff --git a/crates/primitives/genesis-config/Cargo.toml b/crates/primitives/genesis-config/Cargo.toml index 83a76435fd..040591f85b 100644 --- a/crates/primitives/genesis-config/Cargo.toml +++ b/crates/primitives/genesis-config/Cargo.toml @@ -12,8 +12,6 @@ mp-felt = { workspace = true, features = ["parity-scale-codec", "serde"] } blockifier = { workspace = true, features = [ "testing", - "parity-scale-codec", - "scale-info", ] } # # third party diff --git a/crates/primitives/genesis-config/src/lib.rs b/crates/primitives/genesis-config/src/lib.rs index 0c3483a2b7..0aee586f5a 100644 --- a/crates/primitives/genesis-config/src/lib.rs +++ b/crates/primitives/genesis-config/src/lib.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use std::string::String; use std::vec::Vec; -use blockifier::execution::contract_class::ContractClass as StarknetContractClass; use derive_more::Constructor; use mp_felt::Felt252Wrapper; use serde::de::Error; @@ -56,7 +55,8 @@ pub struct GenesisData { pub contracts: Vec<(ContractAddress, ClassHash)>, pub predeployed_accounts: Vec, pub storage: Vec<(ContractStorageKey, StorageValue)>, - pub fee_token_address: ContractAddress, + pub strk_fee_token_address: ContractAddress, + pub eth_fee_token_address: ContractAddress, } #[derive(Constructor)] @@ -74,11 +74,10 @@ impl GenesisLoader { } } -#[derive(Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(untagged)] pub enum ContractClass { Path { path: String, version: u8 }, - Class(StarknetContractClass), } /// A struct containing predeployed accounts info. diff --git a/crates/primitives/messages/Cargo.toml b/crates/primitives/messages/Cargo.toml index 00c8f36d81..8b628bb290 100644 --- a/crates/primitives/messages/Cargo.toml +++ b/crates/primitives/messages/Cargo.toml @@ -26,7 +26,6 @@ serde_with = { workspace = true, optional = true } [features] default = ["std"] std = [ - "starknet_api/std", "mp-transactions/std", "parity-scale-codec?/std", "scale-info?/std", @@ -35,7 +34,6 @@ std = [ ] parity-scale-codec = [ "dep:parity-scale-codec", - "starknet_api/parity-scale-codec", ] -scale-info = ["dep:scale-info", "starknet_api/scale-info"] +scale-info = ["dep:scale-info"] serde = ["dep:serde", "dep:serde_with"] diff --git a/crates/primitives/messages/src/conversions.rs b/crates/primitives/messages/src/conversions.rs index e8046b9edb..6355dbebc1 100644 --- a/crates/primitives/messages/src/conversions.rs +++ b/crates/primitives/messages/src/conversions.rs @@ -1,7 +1,6 @@ -use mp_transactions::HandleL1MessageTransaction; -use starknet_api::api_core::{ContractAddress, EthAddress, Nonce, PatriciaKey}; +use starknet_api::core::{ContractAddress, EthAddress, PatriciaKey}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::MessageToL1; +use starknet_api::transaction::{L1HandlerTransaction, MessageToL1}; use crate::{MessageL1ToL2, MessageL2ToL1}; @@ -18,17 +17,17 @@ impl From for MessageL2ToL1 { } } -impl From for MessageL1ToL2 { - fn from(tx: HandleL1MessageTransaction) -> Self { - let mut calldata = tx.calldata; +impl From for MessageL1ToL2 { + fn from(tx: L1HandlerTransaction) -> Self { + let mut calldata = (*tx.calldata.0).clone(); // Source Eth address is always passed as the first calldata arg - let from_address = ContractAddress(PatriciaKey(StarkFelt::from(calldata.remove(0)))); + let from_address = ContractAddress(PatriciaKey(calldata.remove(0))); Self { from_address, - to_address: tx.contract_address.into(), - nonce: Nonce(tx.nonce.into()), - selector: tx.entry_point_selector.into(), - payload: calldata.into_iter().map(|felt| felt.into()).collect(), + to_address: tx.contract_address, + nonce: tx.nonce, + selector: tx.entry_point_selector, + payload: calldata, } } } diff --git a/crates/primitives/messages/src/lib.rs b/crates/primitives/messages/src/lib.rs index 38cfe80b21..f253a380b4 100644 --- a/crates/primitives/messages/src/lib.rs +++ b/crates/primitives/messages/src/lib.rs @@ -1,12 +1,8 @@ //! L1-L2 messages types definition -#![cfg_attr(not(feature = "std"), no_std)] -#[doc(hidden)] -pub extern crate alloc; +use std::vec::Vec; -use alloc::vec::Vec; - -use starknet_api::api_core::{ContractAddress, EthAddress, Nonce}; +use starknet_api::core::{ContractAddress, EntryPointSelector, EthAddress, Nonce}; use starknet_api::hash::{StarkFelt, StarkHash}; pub mod conversions; @@ -39,7 +35,7 @@ pub struct MessageL1ToL2 { #[cfg_attr(feature = "serde", serde_as(as = "UfeHex"))] pub nonce: Nonce, #[cfg_attr(feature = "serde", serde_as(as = "UfeHex"))] - pub selector: StarkHash, + pub selector: EntryPointSelector, #[cfg_attr(feature = "serde", serde_as(as = "Vec"))] pub payload: Vec, } diff --git a/crates/primitives/simulations/src/lib.rs b/crates/primitives/simulations/src/lib.rs index 2c8221fa05..22306ba744 100644 --- a/crates/primitives/simulations/src/lib.rs +++ b/crates/primitives/simulations/src/lib.rs @@ -23,25 +23,30 @@ pub type TransactionSimulationResult = Result> for SimulationFlags { fn from(flags: Vec) -> Self { - let mut skip_validate = false; - let mut skip_fee_charge = false; + let mut flags_out = Self::default(); for flag in flags { match flag { - SimulationFlag::SkipValidate => skip_validate = true, - SimulationFlag::SkipFeeCharge => skip_fee_charge = true, + SimulationFlag::SkipValidate => flags_out.validate = false, + SimulationFlag::SkipFeeCharge => flags_out.charge_fee = false, } - if skip_validate && skip_fee_charge { + if !flags_out.validate && !flags_out.charge_fee { break; } } - Self { skip_validate, skip_fee_charge } + flags_out + } +} + +impl core::default::Default for SimulationFlags { + fn default() -> Self { + Self { validate: true, charge_fee: true } } } diff --git a/crates/primitives/snos-output/Cargo.toml b/crates/primitives/snos-output/Cargo.toml index e9799da44a..5ff42d824a 100644 --- a/crates/primitives/snos-output/Cargo.toml +++ b/crates/primitives/snos-output/Cargo.toml @@ -28,15 +28,12 @@ std = [ "parity-scale-codec/std", "mp-transactions/std", "mp-messages/std", - "starknet_api/std", ] parity-scale-codec = [ "dep:parity-scale-codec", - "starknet_api/parity-scale-codec", "mp-messages/parity-scale-codec", ] scale-info = [ "dep:scale-info", - "starknet_api/scale-info", "mp-messages/scale-info", ] diff --git a/crates/primitives/snos-output/src/codec.rs b/crates/primitives/snos-output/src/codec.rs index adc0b923ed..b921baf98b 100644 --- a/crates/primitives/snos-output/src/codec.rs +++ b/crates/primitives/snos-output/src/codec.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use mp_messages::conversions::eth_address_to_felt; use mp_messages::{MessageL1ToL2, MessageL2ToL1}; -use starknet_api::api_core::{ContractAddress, EthAddress, Nonce, PatriciaKey}; +use starknet_api::core::{ContractAddress, EntryPointSelector, EthAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use crate::felt_reader::{FeltReader, FeltReaderError}; @@ -92,6 +92,20 @@ impl SnosCodec for Nonce { } } +impl SnosCodec for EntryPointSelector { + fn size_in_felts(&self) -> usize { + 1 + } + + fn encode_to(self, output: &mut Vec) { + output.push(self.0); + } + + fn decode(input: &mut FeltReader) -> Result { + Ok(EntryPointSelector(StarkFelt::decode(input)?)) + } +} + impl SnosCodec for Vec { fn size_in_felts(&self) -> usize { // Works well for Vec @@ -167,7 +181,7 @@ impl SnosCodec for MessageL1ToL2 { from_address: ContractAddress::decode(input)?, to_address: ContractAddress::decode(input)?, nonce: Nonce::decode(input)?, - selector: StarkFelt::decode(input)?, + selector: EntryPointSelector::decode(input)?, payload: Vec::::decode(input)?, }) } diff --git a/crates/primitives/snos-output/src/tests.rs b/crates/primitives/snos-output/src/tests.rs index cf0e4ed05d..bf4c8a40fe 100644 --- a/crates/primitives/snos-output/src/tests.rs +++ b/crates/primitives/snos-output/src/tests.rs @@ -1,5 +1,5 @@ use mp_messages::conversions::eth_address_to_felt; -use starknet_api::api_core::EthAddress; +use starknet_api::core::EthAddress; use starknet_api::hash::StarkFelt; use crate::codec::SnosCodec; diff --git a/crates/primitives/state/Cargo.toml b/crates/primitives/state/Cargo.toml index b3b5a192c8..1f37333111 100644 --- a/crates/primitives/state/Cargo.toml +++ b/crates/primitives/state/Cargo.toml @@ -25,8 +25,6 @@ serde_with = { workspace = true, optional = true } default = ["std"] std = [ "mp-felt/std", - "starknet_api/std", - "blockifier/std", "serde?/std", "serde_with?/std", "parity-scale-codec?/std", @@ -34,8 +32,7 @@ std = [ ] parity-scale-codec = [ "dep:parity-scale-codec", - "starknet_api/parity-scale-codec", "mp-felt/parity-scale-codec", ] serde = ["dep:serde", "dep:serde_with", "mp-felt/serde"] -scale-info = ["dep:scale-info", "starknet_api/scale-info", "mp-felt/scale-info"] +scale-info = ["dep:scale-info", "mp-felt/scale-info"] diff --git a/crates/primitives/state/src/lib.rs b/crates/primitives/state/src/lib.rs index bd8744cdaf..022232d634 100644 --- a/crates/primitives/state/src/lib.rs +++ b/crates/primitives/state/src/lib.rs @@ -1,27 +1,26 @@ //! Starknet state primitives. -#![cfg_attr(not(feature = "std"), no_std)] - #[doc(hidden)] extern crate alloc; +use std::collections::HashMap; + use blockifier::execution::contract_class::ContractClass; -use blockifier::state::cached_state::{ContractStorageKey, StateChangesCount}; use blockifier::state::errors::StateError; use blockifier::state::state_api::{StateReader, StateResult}; -use starknet_api::api_core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; -use starknet_api::stdlib::collections::HashMap; type ContractClassMapping = HashMap; +type ContractStorageKey = (ContractAddress, StorageKey); -/// This trait allows to get the state changes of a starknet tx and therefore enables computing the -/// fees. -pub trait StateChanges { - /// This function counts the storage var updates implied by a transaction and the newly declared - /// class hashes. - fn count_state_changes(&self) -> StateChangesCount; -} +// /// This trait allows to get the state changes of a starknet tx and therefore enables computing +// the /// fees. +// pub trait StateChanges { +// /// This function counts the storage var updates implied by a transaction and the newly +// declared /// class hashes. +// fn count_state_changes(&self) -> StateChangesCount; +// } /// A simple implementation of `StateReader` using `HashMap`s as storage. #[derive(Debug, Default)] @@ -37,31 +36,31 @@ pub struct DictStateReader { } impl StateReader for DictStateReader { - fn get_storage_at(&mut self, contract_address: ContractAddress, key: StorageKey) -> StateResult { + fn get_storage_at(&self, contract_address: ContractAddress, key: StorageKey) -> StateResult { let contract_storage_key = (contract_address, key); let value = self.storage_view.get(&contract_storage_key).copied().unwrap_or_default(); Ok(value) } - fn get_nonce_at(&mut self, contract_address: ContractAddress) -> StateResult { + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { let nonce = self.address_to_nonce.get(&contract_address).copied().unwrap_or_default(); Ok(nonce) } - fn get_compiled_contract_class(&mut self, class_hash: &ClassHash) -> StateResult { - let contract_class = self.class_hash_to_class.get(class_hash).cloned(); + fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { + let contract_class = self.class_hash_to_class.get(&class_hash).cloned(); match contract_class { Some(contract_class) => Ok(contract_class), - None => Err(StateError::UndeclaredClassHash(*class_hash)), + None => Err(StateError::UndeclaredClassHash(class_hash)), } } - fn get_compiled_class_hash(&mut self, _class_hash: ClassHash) -> StateResult { + fn get_compiled_class_hash(&self, _class_hash: ClassHash) -> StateResult { // FIXME 708 Ok(CompiledClassHash::default()) } - fn get_class_hash_at(&mut self, contract_address: ContractAddress) -> StateResult { + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { let class_hash = self.address_to_class_hash.get(&contract_address).copied().unwrap_or_default(); Ok(class_hash) } diff --git a/crates/primitives/state/src/tests.rs b/crates/primitives/state/src/tests.rs index 7fe3917241..1ef0227c4c 100644 --- a/crates/primitives/state/src/tests.rs +++ b/crates/primitives/state/src/tests.rs @@ -1,7 +1,7 @@ use blockifier::execution::contract_class::{ContractClass, ContractClassV0}; use blockifier::state::errors::StateError; use blockifier::state::state_api::StateReader; -use starknet_api::api_core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::core::{ClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; @@ -44,7 +44,7 @@ fn test_get_contract_class() { state.class_hash_to_class.insert(class_hash, contract_class.clone()); - let result = state.get_compiled_contract_class(&class_hash).unwrap(); + let result = state.get_compiled_contract_class(class_hash).unwrap(); assert_eq!(result, contract_class); } @@ -63,11 +63,11 @@ fn test_get_class_hash_at() { #[test] fn test_get_contract_class_undeclared_class_hash() { - let mut state = DictStateReader::default(); + let state = DictStateReader::default(); let undeclared_class_hash = ClassHash::default(); - let result = state.get_compiled_contract_class(&undeclared_class_hash); + let result = state.get_compiled_contract_class(undeclared_class_hash); assert!(result.is_err()); if let Err(StateError::UndeclaredClassHash(hash)) = result { diff --git a/crates/primitives/transactions/Cargo.toml b/crates/primitives/transactions/Cargo.toml index 37e6b51dc8..96d39de494 100644 --- a/crates/primitives/transactions/Cargo.toml +++ b/crates/primitives/transactions/Cargo.toml @@ -14,7 +14,6 @@ targets = ["x86_64-unknown-linux-gnu"] blockifier = { workspace = true } derive_more = { workspace = true, features = ["from"] } log = { workspace = true } -mp-fee = { workspace = true } mp-felt = { workspace = true } mp-hashers = { workspace = true } mp-state = { workspace = true } @@ -22,12 +21,15 @@ starknet-core = { workspace = true } 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 } +cairo-vm = { workspace = true } # Optional (client) -cairo-lang-casm-contract-class = { workspace = true, optional = true } +cairo-lang-starknet-classes = { workspace = true, optional = true } cairo-lang-starknet = { workspace = true, optional = true } cairo-lang-utils = { workspace = true, optional = true } -cairo-vm = { workspace = true, optional = true } flate2 = { workspace = true, optional = true } num-bigint = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } @@ -46,22 +48,17 @@ assert_matches = "1.5.0" [features] default = ["std"] std = [ - "starknet_api/std", "starknet-ff/std", "starknet-core/std", - "blockifier/std", "mp-state/std", "mp-hashers/std", "mp-felt/std", - "mp-fee/std", + "cairo-vm/std", # Optional "parity-scale-codec?/std", "scale-info?/std", "serde?/std", "serde_json?/std", - "cairo-lang-casm-contract-class?/std", - "cairo-lang-utils?/std", - "cairo-vm?/std", ] client = [ "std", @@ -71,19 +68,17 @@ client = [ "dep:num-bigint", "dep:serde_json", "dep:thiserror", - "dep:cairo-vm", - "dep:cairo-lang-casm-contract-class", + "dep:cairo-lang-starknet-classes", ] parity-scale-codec = [ "dep:parity-scale-codec", - "mp-felt/parity-scale-codec", "starknet_api/parity-scale-codec", - "blockifier/parity-scale-codec", + "mp-felt/parity-scale-codec", ] scale-info = [ "dep:scale-info", "mp-felt/scale-info", "starknet_api/scale-info", - "blockifier/scale-info", + "blockifier/scale-info" ] serde = ["dep:serde", "mp-felt/serde"] diff --git a/crates/primitives/transactions/src/compute_hash.rs b/crates/primitives/transactions/src/compute_hash.rs index 0ffeab0491..b53861d245 100644 --- a/crates/primitives/transactions/src/compute_hash.rs +++ b/crates/primitives/transactions/src/compute_hash.rs @@ -1,292 +1,385 @@ use alloc::vec::Vec; 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; +use starknet_api::transaction::{ + Calldata, DeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, DeclareTransactionV3, + DeployAccountTransaction, DeployAccountTransactionV1, DeployAccountTransactionV3, InvokeTransaction, + InvokeTransactionV0, InvokeTransactionV1, InvokeTransactionV3, L1HandlerTransaction, Resource, + ResourceBoundsMapping, TransactionHash, +}; use starknet_core::crypto::compute_hash_on_elements; use starknet_crypto::FieldElement; -use super::{ - DeclareTransaction, DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, DeployAccountTransaction, - HandleL1MessageTransaction, InvokeTransaction, InvokeTransactionV0, InvokeTransactionV1, Transaction, - UserTransaction, SIMULATE_TX_VERSION_OFFSET, -}; -use crate::UserOrL1HandlerTransaction; +use super::SIMULATE_TX_VERSION_OFFSET; const DECLARE_PREFIX: &[u8] = b"declare"; const DEPLOY_ACCOUNT_PREFIX: &[u8] = b"deploy_account"; const INVOKE_PREFIX: &[u8] = b"invoke"; const L1_HANDLER_PREFIX: &[u8] = b"l1_handler"; +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) -> Felt252Wrapper; + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash; +} + +fn convert_calldata(calldata: Calldata) -> Vec { + calldata.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect() } -fn convert_calldata(data: &[Felt252Wrapper]) -> &[FieldElement] { - // Non-copy but less dangerous than transmute - // https://doc.rust-lang.org/std/mem/fn.transmute.html#alternatives - unsafe { core::slice::from_raw_parts(data.as_ptr() as *const FieldElement, data.len()) } +fn prepare_resource_bound_value(resource_bounds_mapping: &ResourceBoundsMapping, resource: Resource) -> FieldElement { + let mut buffer = [0u8; 32]; + buffer[2..8].copy_from_slice(match resource { + Resource::L1Gas => L1_GAS, + Resource::L2Gas => L2_GAS, + }); + if let Some(resource_bounds) = resource_bounds_mapping.0.get(&resource) { + buffer[8..16].copy_from_slice(&resource_bounds.max_amount.to_be_bytes()); + buffer[16..].copy_from_slice(&resource_bounds.max_price_per_unit.to_be_bytes()); + }; + + // Safe to unwrap because we left most significant bit of the buffer empty + FieldElement::from_bytes_be(&buffer).unwrap() +} + +fn prepare_data_availability_modes( + nonce_data_availability_mode: DataAvailabilityMode, + fee_data_availability_mode: DataAvailabilityMode, +) -> FieldElement { + let mut buffer = [0u8; 32]; + buffer[64..96].copy_from_slice(&(nonce_data_availability_mode as u32).to_be_bytes()); + buffer[96..].copy_from_slice(&(fee_data_availability_mode as u32).to_be_bytes()); + + // Safe to unwrap because we left most significant bit of the buffer empty + FieldElement::from_bytes_be(&buffer).unwrap() } impl ComputeTransactionHash for InvokeTransactionV0 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { + 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 = self.contract_address.into(); - let entrypoint_selector = self.entry_point_selector.into(); - let calldata_hash = compute_hash_on_elements(convert_calldata(&self.calldata)); - let max_fee = FieldElement::from(self.max_fee); - let chain_id = chain_id.into(); + let contract_address = Felt252Wrapper::from(self.contract_address).into(); + let entrypoint_selector = Felt252Wrapper::from(self.entry_point_selector).into(); + let calldata_hash = compute_hash_on_elements(&convert_calldata(self.calldata.clone())); + let max_fee = FieldElement::from(self.max_fee.0); - H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, contract_address, entrypoint_selector, calldata_hash, max_fee, - chain_id, - ]) + chain_id.into(), + ])) .into() } } impl ComputeTransactionHash for InvokeTransactionV1 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { + 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 = self.sender_address.into(); + let sender_address = Felt252Wrapper::from(self.sender_address).into(); let entrypoint_selector = FieldElement::ZERO; - let calldata_hash = compute_hash_on_elements(convert_calldata(&self.calldata)); - let max_fee = FieldElement::from(self.max_fee); - let chain_id = chain_id.into(); - let nonce = FieldElement::from(self.nonce); + let calldata_hash = compute_hash_on_elements(&convert_calldata(self.calldata.clone())); + let max_fee = FieldElement::from(self.max_fee.0); + let nonce = Felt252Wrapper::from(self.nonce.0).into(); - H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, sender_address, entrypoint_selector, calldata_hash, max_fee, - chain_id, + chain_id.into(), + nonce, + ])) + .into() + } +} + +impl ComputeTransactionHash for InvokeTransactionV3 { + 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 }; + let sender_address = Felt252Wrapper::from(self.sender_address).into(); + let gas_hash = compute_hash_on_elements(&[ + FieldElement::from(self.tip.0), + prepare_resource_bound_value(&self.resource_bounds, Resource::L1Gas), + prepare_resource_bound_value(&self.resource_bounds, Resource::L2Gas), + ]); + let paymaster_hash = compute_hash_on_elements( + &self.paymaster_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); + let nonce = Felt252Wrapper::from(self.nonce.0).into(); + let data_availability_modes = + prepare_data_availability_modes(self.nonce_data_availability_mode, self.fee_data_availability_mode); + let data_hash = { + let account_deployment_data_hash = compute_hash_on_elements( + &self.account_deployment_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); + let calldata_hash = compute_hash_on_elements( + &self.calldata.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); + compute_hash_on_elements(&[account_deployment_data_hash, calldata_hash]) + }; + + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ + prefix, + version, + sender_address, + gas_hash, + paymaster_hash, + chain_id.into(), nonce, - ]) + data_availability_modes, + data_hash, + ])) .into() } } impl ComputeTransactionHash for InvokeTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { + 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::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), } } } -impl ComputeTransactionHash for DeclareTransactionV0 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { - let prefix = FieldElement::from_byte_slice_be(DECLARE_PREFIX).unwrap(); - let version = if offset_version { SIMULATE_TX_VERSION_OFFSET } else { FieldElement::ZERO }; - let sender_address = self.sender_address.into(); - let entrypoint_selector = FieldElement::ZERO; - let alignment_placeholder = compute_hash_on_elements(&[]); - let max_fee = FieldElement::from(self.max_fee); - let chain_id = chain_id.into(); - let class_hash = self.class_hash.into(); +fn compute_hash_declare_v0_or_v1( + chain_id: Felt252Wrapper, + offset_version: bool, + tx: &DeclareTransactionV0V1, + version: u8, +) -> TransactionHash { + let prefix = FieldElement::from_byte_slice_be(DECLARE_PREFIX).unwrap(); + let sender_address = Felt252Wrapper::from(tx.sender_address).into(); + let zero = FieldElement::ZERO; + let class_or_nothing_hash = if version == 0 { + compute_hash_on_elements(&[]) + } else { + compute_hash_on_elements(&[Felt252Wrapper::from(tx.class_hash).into()]) + }; + let max_fee = FieldElement::from(tx.max_fee.0); + let nonce_or_class_hash = + if version == 0 { Felt252Wrapper::from(tx.class_hash).into() } else { Felt252Wrapper::from(tx.nonce).into() }; + let version = if offset_version { + SIMULATE_TX_VERSION_OFFSET + FieldElement::from(version) + } else { + FieldElement::from(version) + }; - H::compute_hash_on_elements(&[ - prefix, - version, - sender_address, - entrypoint_selector, - alignment_placeholder, - max_fee, - chain_id, - class_hash, - ]) - .into() - } + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ + prefix, + version, + sender_address, + zero, + class_or_nothing_hash, + max_fee, + chain_id.into(), + nonce_or_class_hash, + ])) + .into() } -impl ComputeTransactionHash for DeclareTransactionV1 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { +impl ComputeTransactionHash for DeclareTransactionV2 { + 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::ONE } else { FieldElement::ONE }; - let sender_address = self.sender_address.into(); + let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::TWO } else { FieldElement::TWO }; + let sender_address = Felt252Wrapper::from(self.sender_address).into(); let entrypoint_selector = FieldElement::ZERO; - let calldata = compute_hash_on_elements(&[self.class_hash.into()]); - let max_fee = FieldElement::from(self.max_fee); - let chain_id = chain_id.into(); - let nonce = FieldElement::from(self.nonce); + let calldata = compute_hash_on_elements(&[Felt252Wrapper::from(self.class_hash).into()]); + let max_fee = FieldElement::from(self.max_fee.0); + let nonce = Felt252Wrapper::from(self.nonce).into(); + let compiled_class_hash = Felt252Wrapper::from(self.compiled_class_hash).into(); - H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, sender_address, entrypoint_selector, calldata, max_fee, - chain_id, + chain_id.into(), nonce, - ]) + compiled_class_hash, + ])) .into() } } -impl ComputeTransactionHash for DeclareTransactionV2 { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { +impl ComputeTransactionHash for DeclareTransactionV3 { + 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 = self.sender_address.into(); - let entrypoint_selector = FieldElement::ZERO; - let calldata = compute_hash_on_elements(&[self.class_hash.into()]); - let max_fee = FieldElement::from(self.max_fee); - let chain_id = chain_id.into(); - let nonce = FieldElement::from(self.nonce); - let compiled_class_hash = self.compiled_class_hash.into(); + let version = + if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::THREE } else { FieldElement::THREE }; + let sender_address = Felt252Wrapper::from(self.sender_address).into(); + let gas_hash = compute_hash_on_elements(&[ + FieldElement::from(self.tip.0), + prepare_resource_bound_value(&self.resource_bounds, Resource::L1Gas), + prepare_resource_bound_value(&self.resource_bounds, Resource::L2Gas), + ]); + let paymaster_hash = compute_hash_on_elements( + &self.paymaster_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); + let nonce = Felt252Wrapper::from(self.nonce.0).into(); + let data_availability_modes = + prepare_data_availability_modes(self.nonce_data_availability_mode, self.fee_data_availability_mode); + let account_deployment_data_hash = compute_hash_on_elements( + &self.account_deployment_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); - H::compute_hash_on_elements(&[ + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ prefix, version, sender_address, - entrypoint_selector, - calldata, - max_fee, - chain_id, + gas_hash, + paymaster_hash, + chain_id.into(), nonce, - compiled_class_hash, - ]) + data_availability_modes, + account_deployment_data_hash, + Felt252Wrapper::from(self.class_hash).into(), + Felt252Wrapper::from(self.compiled_class_hash).into(), + ])) .into() } } - impl ComputeTransactionHash for DeclareTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { match self { - DeclareTransaction::V0(tx) => tx.compute_hash::(chain_id, offset_version), - DeclareTransaction::V1(tx) => tx.compute_hash::(chain_id, offset_version), - DeclareTransaction::V2(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) -> Felt252Wrapper { - let chain_id = chain_id.into(); - let contract_address = self.get_account_address(); - - self.compute_hash_given_contract_address::(chain_id, contract_address, offset_version).into() + 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), + } } } -impl DeployAccountTransaction { - pub fn get_account_address(&self) -> FieldElement { - Self::calculate_contract_address( - self.contract_address_salt.into(), - self.class_hash.into(), - convert_calldata(&self.constructor_calldata), - ) - } - - pub fn calculate_contract_address( - contract_address_salt: FieldElement, - class_hash: FieldElement, - constructor_calldata: &[FieldElement], - ) -> FieldElement { - /// Cairo string for "STARKNET_CONTRACT_ADDRESS" - const PREFIX_CONTRACT_ADDRESS: FieldElement = FieldElement::from_mont([ - 3829237882463328880, - 17289941567720117366, - 8635008616843941496, - 533439743893157637, - ]); - // 2 ** 251 - 256 - const ADDR_BOUND: FieldElement = - FieldElement::from_mont([18446743986131443745, 160989183, 18446744073709255680, 576459263475590224]); +impl ComputeTransactionHash for DeployAccountTransactionV1 { + fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> TransactionHash { + let constructor_calldata = convert_calldata(self.constructor_calldata.clone()); - starknet_core::crypto::compute_hash_on_elements(&[ - PREFIX_CONTRACT_ADDRESS, - FieldElement::ZERO, - contract_address_salt, - class_hash, - starknet_core::crypto::compute_hash_on_elements(constructor_calldata), - ]) % ADDR_BOUND - } - - pub(super) fn compute_hash_given_contract_address( - &self, - chain_id: FieldElement, - contract_address: FieldElement, - offset_version: bool, - ) -> FieldElement { + let contract_address = Felt252Wrapper::from( + calculate_contract_address( + self.contract_address_salt, + self.class_hash, + &self.constructor_calldata, + Default::default(), + ) + .unwrap(), + ) + .into(); let prefix = FieldElement::from_byte_slice_be(DEPLOY_ACCOUNT_PREFIX).unwrap(); let version = if offset_version { SIMULATE_TX_VERSION_OFFSET + FieldElement::ONE } else { FieldElement::ONE }; let entrypoint_selector = FieldElement::ZERO; - let mut calldata: Vec = Vec::with_capacity(self.constructor_calldata.len() + 2); - calldata.push(self.class_hash.into()); - calldata.push(self.contract_address_salt.into()); - calldata.extend_from_slice(convert_calldata(&self.constructor_calldata)); + let mut calldata: Vec = Vec::with_capacity(constructor_calldata.len() + 2); + calldata.push(Felt252Wrapper::from(self.class_hash).into()); + calldata.push(Felt252Wrapper::from(self.contract_address_salt).into()); + calldata.extend_from_slice(&constructor_calldata); let calldata_hash = compute_hash_on_elements(&calldata); - let max_fee = FieldElement::from(self.max_fee); - let nonce = FieldElement::from(self.nonce); - let elements = - &[prefix, version, contract_address, entrypoint_selector, calldata_hash, max_fee, chain_id, nonce]; + let max_fee = FieldElement::from(self.max_fee.0); + let nonce = Felt252Wrapper::from(self.nonce).into(); - H::compute_hash_on_elements(elements) - } -} - -impl ComputeTransactionHash for HandleL1MessageTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { - 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 = self.contract_address.into(); - let entrypoint_selector = self.entry_point_selector.into(); - let calldata_hash = compute_hash_on_elements(convert_calldata(&self.calldata)); - let chain_id = chain_id.into(); - let nonce = self.nonce.into(); - - H::compute_hash_on_elements(&[ + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ prefix, version, contract_address, entrypoint_selector, calldata_hash, - chain_id, + max_fee, + chain_id.into(), nonce, - ]) + ])) .into() } } -impl ComputeTransactionHash for Transaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { - match self { - Transaction::Declare(tx, _contract_class) => tx.compute_hash::(chain_id, offset_version), - Transaction::DeployAccount(tx) => tx.compute_hash::(chain_id, offset_version), - Transaction::Invoke(tx) => tx.compute_hash::(chain_id, offset_version), - Transaction::L1Handler(tx) => tx.compute_hash::(chain_id, offset_version), - } - } -} +impl ComputeTransactionHash for DeployAccountTransactionV3 { + 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 }; + let constructor_calldata = convert_calldata(self.constructor_calldata.clone()); + let contract_address = Felt252Wrapper::from( + calculate_contract_address( + self.contract_address_salt, + self.class_hash, + &self.constructor_calldata, + Default::default(), + ) + .unwrap(), + ) + .into(); + let gas_hash = compute_hash_on_elements(&[ + FieldElement::from(self.tip.0), + prepare_resource_bound_value(&self.resource_bounds, Resource::L1Gas), + prepare_resource_bound_value(&self.resource_bounds, Resource::L2Gas), + ]); + let paymaster_hash = compute_hash_on_elements( + &self.paymaster_data.0.iter().map(|f| Felt252Wrapper::from(*f).into()).collect::>(), + ); + let nonce = Felt252Wrapper::from(self.nonce.0).into(); + let data_availability_modes = + prepare_data_availability_modes(self.nonce_data_availability_mode, self.fee_data_availability_mode); + let constructor_calldata_hash = compute_hash_on_elements(&constructor_calldata); -impl ComputeTransactionHash for UserTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { - match self { - UserTransaction::Declare(tx, _) => tx.compute_hash::(chain_id, offset_version), - UserTransaction::DeployAccount(tx) => tx.compute_hash::(chain_id, offset_version), - UserTransaction::Invoke(tx) => tx.compute_hash::(chain_id, offset_version), - } + Felt252Wrapper(PoseidonHasher::compute_hash_on_elements(&[ + prefix, + version, + contract_address, + gas_hash, + paymaster_hash, + chain_id.into(), + nonce, + data_availability_modes, + constructor_calldata_hash, + Felt252Wrapper::from(self.class_hash).into(), + Felt252Wrapper::from(self.contract_address_salt).into(), + ])) + .into() } } -impl ComputeTransactionHash for UserOrL1HandlerTransaction { - fn compute_hash(&self, chain_id: Felt252Wrapper, offset_version: bool) -> Felt252Wrapper { - match self { - UserOrL1HandlerTransaction::User(tx) => tx.compute_hash::(chain_id, offset_version), - UserOrL1HandlerTransaction::L1Handler(tx, _) => tx.compute_hash::(chain_id, offset_version), - } +impl ComputeTransactionHash for L1HandlerTransaction { + 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(); + let entrypoint_selector = Felt252Wrapper::from(self.entry_point_selector).into(); + let calldata_hash = compute_hash_on_elements(&convert_calldata(self.calldata.clone())); + let nonce = Felt252Wrapper::from(self.nonce).into(); + + Felt252Wrapper(PedersenHasher::compute_hash_on_elements(&[ + prefix, + version, + contract_address, + entrypoint_selector, + calldata_hash, + chain_id.into(), + nonce, + ])) + .into() } } diff --git a/crates/primitives/transactions/src/compute_hash_tests.rs b/crates/primitives/transactions/src/compute_hash_tests.rs index d5d8649ecb..a30f1d8b4a 100644 --- a/crates/primitives/transactions/src/compute_hash_tests.rs +++ b/crates/primitives/transactions/src/compute_hash_tests.rs @@ -1,269 +1,149 @@ use alloc::sync::Arc; -use blockifier::execution::contract_class::ContractClass; use mp_felt::Felt252Wrapper; -use mp_hashers::pedersen::PedersenHasher; -use starknet_api::api_core::{calculate_contract_address, ContractAddress, PatriciaKey}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::Calldata; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, DeclareTransaction, DeclareTransactionV0V1, DeclareTransactionV2, + DeployAccountTransactionV1, Fee, InvokeTransactionV1, L1HandlerTransaction, TransactionHash, TransactionSignature, +}; use starknet_crypto::FieldElement; use crate::compute_hash::ComputeTransactionHash; -use crate::{ - DeclareTransaction, DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, DeployAccountTransaction, - HandleL1MessageTransaction, InvokeTransaction, InvokeTransactionV0, InvokeTransactionV1, Transaction, - UserTransaction, -}; - -#[test] -fn compute_contract_address_work_like_starknet_api_impl() { - let tx = DeployAccountTransaction { - max_fee: Default::default(), - signature: Default::default(), - nonce: Default::default(), - contract_address_salt: Felt252Wrapper::ZERO, - constructor_calldata: vec![Felt252Wrapper::ONE, Felt252Wrapper::TWO], - class_hash: Felt252Wrapper::THREE, - offset_version: false, - }; - - let address = tx.get_account_address(); - - let expected_address = calculate_contract_address( - tx.contract_address_salt.into(), - tx.class_hash.into(), - &Calldata(Arc::new(vec![StarkFelt::from(1u128), StarkFelt::from(2u128)])), - ContractAddress(PatriciaKey(StarkFelt::from(0u128))), - ) - .unwrap(); - - assert_eq!(Felt252Wrapper(address), expected_address.into()); -} #[test] fn test_deploy_account_tx_hash() { // Computed with `calculateDeployAccountTransactionHash` from the starknet.js - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x04cf7bf97d4f8ef73eb83d2e6fb8e5354c04f2121b9bd38510220eff3a07e9df").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x04cf7bf97d4f8ef73eb83d2e6fb8e5354c04f2121b9bd38510220eff3a07e9df").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); - let transaction = DeployAccountTransaction { - max_fee: 1, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - constructor_calldata: vec![Felt252Wrapper::ONE, Felt252Wrapper::TWO, Felt252Wrapper::THREE], - contract_address_salt: Felt252Wrapper::ZERO, - class_hash: Felt252Wrapper::THREE, - offset_version: false, + let transaction = DeployAccountTransactionV1 { + max_fee: Fee(1), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + constructor_calldata: Calldata(Arc::new(vec![StarkFelt::ONE, StarkFelt::TWO, StarkFelt::THREE])), + contract_address_salt: ContractAddressSalt(StarkFelt::ZERO), + class_hash: ClassHash(StarkFelt::THREE), }; - let tx_hash = transaction.compute_hash::(chain_id, false); - - assert_eq!(tx_hash, expected_tx_hash); - - let generic_transaction = Transaction::DeployAccount(transaction.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); + let tx_hash = transaction.compute_hash(chain_id, false); - let user_transaction = UserTransaction::DeployAccount(transaction); - let tx_hash = user_transaction.compute_hash::(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } #[test] fn test_declare_v0_tx_hash() { // Computed with `calculate_declare_transaction_hash` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x052b849ca86ca1a1ce6ac7e069900a221b5741786bffe023804ef714f7bb46da").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x052b849ca86ca1a1ce6ac7e069900a221b5741786bffe023804ef714f7bb46da").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); - let transaction = DeclareTransactionV0 { - max_fee: 1, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - class_hash: Felt252Wrapper::THREE, - sender_address: Felt252Wrapper::from(19911991_u128), - }; + let transaction = DeclareTransaction::V0(DeclareTransactionV0V1 { + max_fee: Fee(1), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + class_hash: ClassHash(StarkFelt::THREE), + 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); - - let contract_class = ContractClass::V0(Default::default()); - - let declare_v0_transaction = DeclareTransaction::V0(transaction); - let tx_hash = declare_v0_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let generic_transaction = Transaction::Declare(declare_v0_transaction.clone(), contract_class.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let user_transaction = UserTransaction::Declare(declare_v0_transaction, contract_class); - let tx_hash = user_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); } #[test] fn test_declare_v1_tx_hash() { // Computed with `calculate_declare_transaction_hash` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x077f205d4855199564663dc9810c1edfcf97573393033dedc3f12dac740aac13").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x077f205d4855199564663dc9810c1edfcf97573393033dedc3f12dac740aac13").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); - let transaction = DeclareTransactionV1 { - max_fee: 1, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - class_hash: Felt252Wrapper::THREE, - sender_address: Felt252Wrapper::from(19911991_u128), - offset_version: false, - }; - - let tx_hash = transaction.compute_hash::(chain_id, false); + let transaction = DeclareTransaction::V1(DeclareTransactionV0V1 { + max_fee: Fee(1), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + class_hash: ClassHash(StarkFelt::THREE), + sender_address: ContractAddress(PatriciaKey(StarkFelt::from(19911991_u128))), + }); - assert_eq!(tx_hash, expected_tx_hash); - - let declare_v1_transaction = DeclareTransaction::V1(transaction); - let tx_hash = declare_v1_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let contract_class = ContractClass::V0(Default::default()); - let generic_transaction = Transaction::Declare(declare_v1_transaction.clone(), contract_class.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let user_transaction = UserTransaction::Declare(declare_v1_transaction, contract_class); - let tx_hash = user_transaction.compute_hash::(chain_id, false); + let tx_hash = transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } #[test] fn test_declare_v2_tx_hash() { // Computed with `calculate_declare_transaction_hash` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x7ca2d13e00a7249a7f61cf65c20a20f2870276d4db00d816e836eb2ca9029ae").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x7ca2d13e00a7249a7f61cf65c20a20f2870276d4db00d816e836eb2ca9029ae").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); let transaction = DeclareTransactionV2 { - max_fee: 1, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - class_hash: Felt252Wrapper::THREE, - sender_address: Felt252Wrapper::from(19911991_u128), - compiled_class_hash: Felt252Wrapper::THREE, - offset_version: false, + max_fee: Fee(1), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + class_hash: ClassHash(StarkFelt::THREE), + sender_address: ContractAddress(PatriciaKey(StarkFelt::from(19911991_u128))), + 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); - assert_eq!(tx_hash, expected_tx_hash); - - let contract_class = ContractClass::V1(Default::default()); - let generic_transaction = Transaction::Declare(declare_v2_transaction.clone(), contract_class.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let user_transaction = UserTransaction::Declare(declare_v2_transaction, contract_class); - let tx_hash = user_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); -} - -#[test] -fn test_invoke_tx_v0_hash() { - // Computed with `calculate_transaction_hash_common` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x0006a8aca140749156148fa84f432f7f7b7318c119d97dd1808848fc74d1a8a6").unwrap(); - - let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); - - let transaction = InvokeTransactionV0 { - max_fee: 1, - signature: vec![], - contract_address: Default::default(), - entry_point_selector: Default::default(), - calldata: vec![Felt252Wrapper::ONE, Felt252Wrapper::TWO, Felt252Wrapper::THREE], - }; - - let tx_hash = transaction.compute_hash::(chain_id, false); - - assert_eq!(tx_hash, expected_tx_hash); - - let invoke_v0_transaction = InvokeTransaction::V0(transaction); - let tx_hash = invoke_v0_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let generic_transaction = Transaction::Invoke(invoke_v0_transaction.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let user_transaction = UserTransaction::Invoke(invoke_v0_transaction.clone()); - let tx_hash = user_transaction.compute_hash::(chain_id, false); + let tx_hash = declare_v2_transaction.compute_hash(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } #[test] fn test_invoke_tx_v1_hash() { // Computed with `calculate_transaction_hash_common` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x062633b1f3d64708df3d0d44706b388f841ed4534346be6ad60336c8eb2f4b3e").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x062633b1f3d64708df3d0d44706b388f841ed4534346be6ad60336c8eb2f4b3e").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); let transaction = InvokeTransactionV1 { - max_fee: 1, - signature: vec![], - nonce: Felt252Wrapper::ZERO, - sender_address: Felt252Wrapper::from(19911991_u128), - calldata: vec![Felt252Wrapper::ONE, Felt252Wrapper::TWO, Felt252Wrapper::THREE], - offset_version: false, + max_fee: Fee(1), + signature: TransactionSignature(vec![]), + nonce: Nonce(StarkFelt::ZERO), + sender_address: ContractAddress(PatriciaKey(StarkFelt::from(19911991_u128))), + 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); - - let invoke_v1_transaction = InvokeTransaction::V1(transaction); - let tx_hash = invoke_v1_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let generic_transaction = Transaction::Invoke(invoke_v1_transaction.clone()); - let tx_hash = generic_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); - - let user_transaction = UserTransaction::Invoke(invoke_v1_transaction); - let tx_hash = user_transaction.compute_hash::(chain_id, false); - assert_eq!(tx_hash, expected_tx_hash); } #[test] fn test_handle_l1_message_tx_hash() { // Computed with `calculate_transaction_hash_common` from the cairo lang package - let expected_tx_hash = - Felt252Wrapper::from_hex_be("0x023f18bb43e61985fba987824a9b8fdea96276e38e34702c72de4250ba91f518").unwrap(); + let expected_tx_hash = TransactionHash( + StarkFelt::try_from("0x023f18bb43e61985fba987824a9b8fdea96276e38e34702c72de4250ba91f518").unwrap(), + ); let chain_id = Felt252Wrapper(FieldElement::from_byte_slice_be(b"SN_GOERLI").unwrap()); - let transaction = HandleL1MessageTransaction { + let transaction = L1HandlerTransaction { nonce: Default::default(), contract_address: Default::default(), entry_point_selector: Default::default(), calldata: Default::default(), + version: Default::default(), }; - let tx_hash = transaction.compute_hash::(chain_id, false); - - assert_eq!(tx_hash, expected_tx_hash); + let tx_hash = transaction.compute_hash(chain_id, false); - let wrapped_transaction = Transaction::L1Handler(transaction.clone()); - let tx_hash = wrapped_transaction.compute_hash::(chain_id, false); assert_eq!(tx_hash, expected_tx_hash); } diff --git a/crates/primitives/transactions/src/conversions.rs b/crates/primitives/transactions/src/conversions.rs index 283d1eb533..b07f437fab 100644 --- a/crates/primitives/transactions/src/conversions.rs +++ b/crates/primitives/transactions/src/conversions.rs @@ -1,11 +1,11 @@ use alloc::sync::Arc; -use blockifier::execution::contract_class::ContractClass; +use blockifier::execution::contract_class::{ClassInfo, ContractClass}; use blockifier::transaction::objects::TransactionExecutionResult; use blockifier::transaction::transactions as btx; use mp_felt::Felt252Wrapper; use mp_hashers::HasherT; -use starknet_api::api_core::Nonce; +use starknet_api::core::Nonce; use starknet_api::hash::StarkFelt; use starknet_api::transaction as sttx; use starknet_api::transaction::{Fee, TransactionVersion}; @@ -13,7 +13,7 @@ use starknet_api::transaction::{Fee, TransactionVersion}; use super::compute_hash::ComputeTransactionHash; use super::{ DeclareTransaction, DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, DeployAccountTransaction, - HandleL1MessageTransaction, InvokeTransaction, InvokeTransactionV0, InvokeTransactionV1, + HandleL1MessageTransaction, InvokeTransaction, InvokeTransactionV1, }; impl DeclareTransactionV0 { @@ -25,6 +25,10 @@ impl DeclareTransactionV0 { ) -> TransactionExecutionResult { let transaction_hash = self.compute_hash::(chain_id, offset_version); + // TODO: Stop using our custom types + // I pass fake values so it don't crash, but will result in unrealistic fees + let class_info = ClassInfo::new(&contract_class, 0, 0).unwrap(); + btx::DeclareTransaction::new( sttx::DeclareTransaction::V0(sttx::DeclareTransactionV0V1 { max_fee: sttx::Fee(self.max_fee), @@ -34,7 +38,7 @@ impl DeclareTransactionV0 { sender_address: self.sender_address.into(), }), transaction_hash.into(), - contract_class, + class_info, ) } } @@ -48,6 +52,10 @@ impl DeclareTransactionV1 { ) -> TransactionExecutionResult { let transaction_hash = self.compute_hash::(chain_id, offset_version); + // TODO: Stop using our custom types + // I pass fake values so it don't crash, but will result in unrealistic fees + let class_info = ClassInfo::new(&contract_class, 1, 0).unwrap(); + btx::DeclareTransaction::new( sttx::DeclareTransaction::V1(sttx::DeclareTransactionV0V1 { max_fee: sttx::Fee(self.max_fee), @@ -57,7 +65,7 @@ impl DeclareTransactionV1 { sender_address: self.sender_address.into(), }), transaction_hash.into(), - contract_class, + class_info, ) } } @@ -71,6 +79,10 @@ impl DeclareTransactionV2 { ) -> TransactionExecutionResult { let transaction_hash = self.compute_hash::(chain_id, offset_version); + // TODO: Stop using our custom types + // I pass fake values so it don't crash, but will result in unrealistic fees + let class_info = ClassInfo::new(&contract_class, 1, 0).unwrap(); + btx::DeclareTransaction::new( sttx::DeclareTransaction::V2(sttx::DeclareTransactionV2 { max_fee: sttx::Fee(self.max_fee), @@ -81,7 +93,7 @@ impl DeclareTransactionV2 { sender_address: self.sender_address.into(), }), transaction_hash.into(), - contract_class, + class_info, ) } } @@ -101,27 +113,6 @@ impl DeclareTransaction { } } -impl InvokeTransactionV0 { - pub fn into_executable( - &self, - chain_id: Felt252Wrapper, - offset_version: bool, - ) -> btx::InvokeTransaction { - let transaction_hash = self.compute_hash::(chain_id, offset_version); - - btx::InvokeTransaction { - tx: sttx::InvokeTransaction::V0(sttx::InvokeTransactionV0 { - max_fee: sttx::Fee(self.max_fee), - signature: vec_of_felt_to_signature(&self.signature), - contract_address: self.contract_address.into(), - entry_point_selector: self.entry_point_selector.into(), - calldata: vec_of_felt_to_calldata(&self.calldata), - }), - tx_hash: transaction_hash.into(), - } - } -} - impl InvokeTransactionV1 { pub fn into_executable( &self, @@ -139,6 +130,7 @@ impl InvokeTransactionV1 { sender_address: self.sender_address.into(), }), tx_hash: transaction_hash.into(), + only_query: offset_version, } } } @@ -150,7 +142,6 @@ impl InvokeTransaction { offset_version: bool, ) -> btx::InvokeTransaction { match self { - InvokeTransaction::V0(tx) => tx.into_executable::(chain_id, offset_version), InvokeTransaction::V1(tx) => tx.into_executable::(chain_id, offset_version), } } @@ -167,18 +158,20 @@ impl DeployAccountTransaction { self.compute_hash_given_contract_address::(chain_id.into(), account_address, offset_version).into(); let contract_address: Felt252Wrapper = account_address.into(); + let tx = sttx::DeployAccountTransaction::V1(sttx::DeployAccountTransactionV1 { + max_fee: sttx::Fee(self.max_fee), + signature: vec_of_felt_to_signature(&self.signature), + nonce: self.nonce.into(), + class_hash: self.class_hash.into(), + contract_address_salt: self.contract_address_salt.into(), + constructor_calldata: vec_of_felt_to_calldata(&self.constructor_calldata), + }); + btx::DeployAccountTransaction { - tx: sttx::DeployAccountTransaction { - max_fee: sttx::Fee(self.max_fee), - version: sttx::TransactionVersion(StarkFelt::from(1u128)), - signature: vec_of_felt_to_signature(&self.signature), - nonce: self.nonce.into(), - class_hash: self.class_hash.into(), - contract_address_salt: self.contract_address_salt.into(), - constructor_calldata: vec_of_felt_to_calldata(&self.constructor_calldata), - }, + tx, tx_hash: transaction_hash.into(), contract_address: contract_address.into(), + only_query: offset_version, } } } diff --git a/crates/primitives/transactions/src/execution.rs b/crates/primitives/transactions/src/execution.rs index 267a07e7d7..e47c403dd5 100644 --- a/crates/primitives/transactions/src/execution.rs +++ b/crates/primitives/transactions/src/execution.rs @@ -1,39 +1,38 @@ -use alloc::string::String; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; +use std::collections::HashSet; use blockifier::abi::abi_utils::selector_from_name; -use blockifier::abi::constants::{INITIAL_GAS_COST, TRANSACTION_GAS_COST}; -use blockifier::block_context::BlockContext; -use blockifier::execution::entry_point::{ - CallEntryPoint, CallInfo, CallType, EntryPointExecutionContext, ExecutionResources, -}; -use blockifier::state::state_api::State; -use blockifier::transaction::constants::{ - VALIDATE_DECLARE_ENTRY_POINT_NAME, VALIDATE_DEPLOY_ENTRY_POINT_NAME, VALIDATE_ENTRY_POINT_NAME, -}; -use blockifier::transaction::errors::TransactionExecutionError; +use blockifier::context::{BlockContext, TransactionContext}; +use blockifier::execution::call_info::{CallInfo, Retdata}; +use blockifier::execution::contract_class::ContractClass; +use blockifier::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; +use blockifier::fee::actual_cost::{ActualCost, ActualCostBuilder}; +use blockifier::fee::fee_checks::{FeeCheckReportFields, PostExecutionReport}; +use blockifier::state::cached_state::{CachedState, GlobalContractCache, StateChangesCount}; +use blockifier::state::state_api::{State, StateReader, StateResult}; +use blockifier::transaction::account_transaction::{AccountTransaction, ValidateExecuteCallInfo}; +use blockifier::transaction::errors::{TransactionExecutionError, TransactionFeeError, TransactionPreValidationError}; use blockifier::transaction::objects::{ - AccountTransactionContext, ResourcesMapping, TransactionExecutionInfo, TransactionExecutionResult, + GasVector, HasRelatedFeeType, ResourcesMapping, TransactionExecutionInfo, TransactionExecutionResult, + TransactionInfo, TransactionInfoCreator, }; use blockifier::transaction::transaction_types::TransactionType; -use blockifier::transaction::transaction_utils::{update_remaining_gas, verify_no_calls_to_other_contracts}; use blockifier::transaction::transactions::{ DeclareTransaction, DeployAccountTransaction, Executable, InvokeTransaction, L1HandlerTransaction, }; -use mp_fee::{calculate_tx_fee, charge_fee, compute_transaction_resources}; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use indexmap::IndexMap; use mp_felt::Felt252Wrapper; -use mp_state::StateChanges; -use starknet_api::api_core::{ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::deprecated_contract_class::EntryPointType; use starknet_api::hash::StarkFelt; -use starknet_api::transaction::{Calldata, Fee, TransactionSignature, TransactionVersion}; +use starknet_api::state::StorageKey; +use starknet_api::transaction::{Calldata, Fee, ResourceBounds, TransactionVersion}; use super::SIMULATE_TX_VERSION_OFFSET; -const TX_INITIAL_AVAILABLE_GAS: u64 = INITIAL_GAS_COST - TRANSACTION_GAS_COST; - /// Contains the execution configuration regarding transaction fee /// activation, transaction fee charging, nonce validation, transaction /// validation and the execution mode (query or not). @@ -61,26 +60,6 @@ impl ExecutionConfig { } } -pub struct ValidateExecuteCallInfo { - pub validate_call_info: Option, - pub execute_call_info: Option, - pub revert_error: Option, -} - -impl ValidateExecuteCallInfo { - fn new_accepted(validate_call_info: Option, execute_call_info: Option) -> Self { - Self { validate_call_info, execute_call_info, revert_error: None } - } - - fn new_reverted(validate_call_info: Option, revert_error: String) -> Self { - Self { validate_call_info, execute_call_info: None, revert_error: Some(revert_error) } - } -} - -pub trait GetAccountTransactionContext { - fn get_account_transaction_context(&self, offset_version: bool) -> AccountTransactionContext; -} - pub trait SimulateTxVersionOffset { fn apply_simulate_tx_version_offset(&self) -> TransactionVersion; } @@ -91,120 +70,54 @@ impl SimulateTxVersionOffset for TransactionVersion { } } -impl GetAccountTransactionContext for DeclareTransaction { - fn get_account_transaction_context(&self, offset_version: bool) -> AccountTransactionContext { - let mut version = self.tx().version(); - if offset_version { - version = version.apply_simulate_tx_version_offset(); - } - - AccountTransactionContext { - transaction_hash: self.tx_hash(), - max_fee: self.tx().max_fee(), - version, - signature: self.tx().signature(), - nonce: self.tx().nonce(), - sender_address: self.tx().sender_address(), - } - } +pub trait GetValidateEntryPointCalldata { + fn get_validate_entry_point_calldata(&self) -> Calldata; } -impl GetAccountTransactionContext for DeployAccountTransaction { - fn get_account_transaction_context(&self, offset_version: bool) -> AccountTransactionContext { - let mut version = self.version(); - if offset_version { - version = version.apply_simulate_tx_version_offset(); - } - - AccountTransactionContext { - transaction_hash: self.tx_hash, - max_fee: self.max_fee(), - version, - signature: self.signature(), - nonce: self.nonce(), - sender_address: self.contract_address, - } +impl GetValidateEntryPointCalldata for DeclareTransaction { + fn get_validate_entry_point_calldata(&self) -> Calldata { + Calldata(Arc::new(vec![self.tx().class_hash().0])) } } -impl GetAccountTransactionContext for InvokeTransaction { - fn get_account_transaction_context(&self, offset_version: bool) -> AccountTransactionContext { - let mut version = match self.tx { - starknet_api::transaction::InvokeTransaction::V0(_) => TransactionVersion(StarkFelt::from(0u8)), - starknet_api::transaction::InvokeTransaction::V1(_) => TransactionVersion(StarkFelt::from(1u8)), - }; - if offset_version { - version = version.apply_simulate_tx_version_offset(); - } - - let nonce = match &self.tx { - starknet_api::transaction::InvokeTransaction::V0(_) => Nonce::default(), - starknet_api::transaction::InvokeTransaction::V1(tx) => tx.nonce, - }; - - let sender_address = match &self.tx { - starknet_api::transaction::InvokeTransaction::V0(tx) => tx.contract_address, - starknet_api::transaction::InvokeTransaction::V1(tx) => tx.sender_address, - }; - - AccountTransactionContext { - transaction_hash: self.tx_hash, - max_fee: self.max_fee(), - version, - signature: self.signature(), - nonce, - sender_address, - } +impl GetValidateEntryPointCalldata for DeployAccountTransaction { + fn get_validate_entry_point_calldata(&self) -> Calldata { + let mut validate_calldata = Vec::with_capacity(self.tx().constructor_calldata().0.len() + 2); + validate_calldata.push(self.tx.class_hash().0); + validate_calldata.push(self.tx.contract_address_salt().0); + validate_calldata.extend_from_slice(&(self.tx.constructor_calldata().0)); + Calldata(validate_calldata.into()) } } -impl GetAccountTransactionContext for L1HandlerTransaction { - fn get_account_transaction_context(&self, offset_version: bool) -> AccountTransactionContext { - let mut version = self.tx.version; - if offset_version { - version = version.apply_simulate_tx_version_offset(); - } - - AccountTransactionContext { - transaction_hash: self.tx_hash, - max_fee: Fee::default(), - version, - signature: TransactionSignature::default(), - nonce: self.tx.nonce, - sender_address: self.tx.contract_address, - } +impl GetValidateEntryPointCalldata for InvokeTransaction { + fn get_validate_entry_point_calldata(&self) -> Calldata { + self.tx.calldata() } } -pub trait GetTransactionCalldata { - fn calldata(&self) -> Calldata; -} - -impl GetTransactionCalldata for DeclareTransaction { - fn calldata(&self) -> Calldata { - Calldata(Arc::new(vec![self.tx().class_hash().0])) +impl GetValidateEntryPointCalldata for L1HandlerTransaction { + fn get_validate_entry_point_calldata(&self) -> Calldata { + self.tx.calldata.clone() } } -impl GetTransactionCalldata for DeployAccountTransaction { - fn calldata(&self) -> Calldata { - let mut validate_calldata = Vec::with_capacity((*self.tx.constructor_calldata.0).len() + 2); - validate_calldata.push(self.tx.class_hash.0); - validate_calldata.push(self.tx.contract_address_salt.0); - validate_calldata.extend_from_slice(&(self.tx.constructor_calldata.0)); - Calldata(validate_calldata.into()) +pub trait GetCalldataLen { + fn get_calldata_len(&self) -> usize; +} +impl GetCalldataLen for DeclareTransaction { + fn get_calldata_len(&self) -> usize { + 0 } } - -impl GetTransactionCalldata for InvokeTransaction { - fn calldata(&self) -> Calldata { - self.calldata() +impl GetCalldataLen for DeployAccountTransaction { + fn get_calldata_len(&self) -> usize { + self.tx.constructor_calldata().0.len() } } - -impl GetTransactionCalldata for L1HandlerTransaction { - fn calldata(&self) -> Calldata { - self.tx.calldata.clone() +impl GetCalldataLen for InvokeTransaction { + fn get_calldata_len(&self) -> usize { + self.tx.calldata().0.len() } } @@ -233,48 +146,300 @@ impl GetTxType for L1HandlerTransaction { } } -pub trait Validate: GetAccountTransactionContext + GetTransactionCalldata { - const VALIDATE_TX_ENTRY_POINT_NAME: &'static str; +pub trait HandleNonce { + fn handle_nonce(state: &mut dyn State, tx_info: &TransactionInfo, strict: bool) -> TransactionExecutionResult<()> { + if tx_info.is_v0() { + return Ok(()); + } + + let address = tx_info.sender_address(); + let account_nonce = state.get_nonce_at(address)?; + let incoming_tx_nonce = tx_info.nonce(); + let valid_nonce = if strict { account_nonce == incoming_tx_nonce } else { account_nonce <= incoming_tx_nonce }; + + if valid_nonce { + state.increment_nonce(address)?; + Ok(()) + } else { + Err(TransactionPreValidationError::InvalidNonce { address, account_nonce, incoming_tx_nonce }.into()) + } + } +} + +impl HandleNonce for DeclareTransaction {} +impl HandleNonce for DeployAccountTransaction {} +impl HandleNonce for InvokeTransaction {} + +pub trait GetActualCostBuilder { + fn get_actual_cost_builder(&self, tx_context: Arc) -> ActualCostBuilder<'_>; +} + +impl GetActualCostBuilder for InvokeTransaction { + fn get_actual_cost_builder(&self, tx_context: Arc) -> ActualCostBuilder<'_> { + ActualCostBuilder::new(tx_context, Self::tx_type(), self.get_calldata_len(), self.tx.signature().0.len()) + } +} +impl GetActualCostBuilder for DeployAccountTransaction { + fn get_actual_cost_builder(&self, tx_context: Arc) -> ActualCostBuilder<'_> { + ActualCostBuilder::new(tx_context, Self::tx_type(), self.get_calldata_len(), self.tx.signature().0.len()) + } +} +impl GetActualCostBuilder for DeclareTransaction { + fn get_actual_cost_builder(&self, tx_context: Arc) -> ActualCostBuilder<'_> { + let mut actual_cost_builder = + ActualCostBuilder::new(tx_context, Self::tx_type(), self.get_calldata_len(), self.tx.signature().0.len()); + actual_cost_builder = actual_cost_builder.with_class_info(self.class_info.clone()); + + actual_cost_builder + } +} + +pub trait CheckFeeBounds: GetCalldataLen + GetTxType { + fn state_changes() -> StateChangesCount; + + fn check_fee_bounds(&self, tx_context: &TransactionContext) -> TransactionExecutionResult<()> { + let minimal_l1_gas_amount_vector = { + let block_info = tx_context.block_context.block_info(); + let versioned_constants = tx_context.block_context.versioned_constants(); + + let state_changes = Self::state_changes(); + + let GasVector { l1_gas: gas_cost, l1_data_gas: blob_gas_cost } = + blockifier::fee::gas_usage::get_da_gas_cost(&state_changes, block_info.use_kzg_da); + + let data_segment_length = blockifier::fee::gas_usage::get_onchain_data_segment_length(&state_changes); + let os_steps_for_type = + versioned_constants.os_resources_for_tx_type(&Self::tx_type(), self.get_calldata_len()).n_steps + + versioned_constants.os_kzg_da_resources(data_segment_length).n_steps; + + let resources = ResourcesMapping(IndexMap::from([ + (blockifier::abi::constants::L1_GAS_USAGE.to_string(), gas_cost), + (blockifier::abi::constants::BLOB_GAS_USAGE.to_string(), blob_gas_cost), + (blockifier::abi::constants::N_STEPS_RESOURCE.to_string(), os_steps_for_type as u128), + ])); + + blockifier::fee::fee_utils::calculate_tx_gas_vector(&resources, versioned_constants)? + }; + + // TODO(Aner, 30/01/24): modify once data gas limit is enforced. + let minimal_l1_gas_amount = blockifier::fee::gas_usage::compute_discounted_gas_from_gas_vector( + &minimal_l1_gas_amount_vector, + tx_context, + ); + + let TransactionContext { block_context, tx_info } = tx_context; + let block_info = block_context.block_info(); + let fee_type = &tx_info.fee_type(); + + match tx_info { + TransactionInfo::Current(context) => { + let ResourceBounds { max_amount: max_l1_gas_amount, max_price_per_unit: max_l1_gas_price } = + context.l1_resource_bounds()?; + + let max_l1_gas_amount_as_u128: u128 = max_l1_gas_amount.into(); + if max_l1_gas_amount_as_u128 < minimal_l1_gas_amount { + return Err(TransactionFeeError::MaxL1GasAmountTooLow { + max_l1_gas_amount, + // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why + // the convertion works. + minimal_l1_gas_amount: (minimal_l1_gas_amount + .try_into() + .expect("Failed to convert u128 to u64.")), + })?; + } + + let actual_l1_gas_price = block_info.gas_prices.get_gas_price_by_fee_type(fee_type); + if max_l1_gas_price < actual_l1_gas_price.into() { + return Err(TransactionFeeError::MaxL1GasPriceTooLow { + max_l1_gas_price, + actual_l1_gas_price: actual_l1_gas_price.into(), + })?; + } + } + TransactionInfo::Deprecated(context) => { + let max_fee = context.max_fee; + let min_fee = blockifier::fee::fee_utils::get_fee_by_gas_vector( + block_info, + minimal_l1_gas_amount_vector, + fee_type, + ); + if max_fee < min_fee { + return Err(TransactionFeeError::MaxFeeTooLow { min_fee, max_fee })?; + } + } + }; + + Ok(()) + } +} + +impl CheckFeeBounds for DeclareTransaction { + fn state_changes() -> StateChangesCount { + StateChangesCount { + n_storage_updates: 1, + n_class_hash_updates: 0, + n_compiled_class_hash_updates: 0, + n_modified_contracts: 1, + } + } +} + +impl CheckFeeBounds for DeployAccountTransaction { + fn state_changes() -> StateChangesCount { + StateChangesCount { + n_storage_updates: 1, + n_class_hash_updates: 1, + n_compiled_class_hash_updates: 0, + n_modified_contracts: 1, + } + } +} - fn validate_entry_point_selector(&self) -> EntryPointSelector { - selector_from_name(Self::VALIDATE_TX_ENTRY_POINT_NAME) +impl CheckFeeBounds for InvokeTransaction { + fn state_changes() -> StateChangesCount { + StateChangesCount { + n_storage_updates: 1, + n_class_hash_updates: 0, + n_compiled_class_hash_updates: 0, + n_modified_contracts: 1, + } } +} - fn validate_tx( +pub trait GetValidateEntryPointSelector { + fn get_validate_entry_point_selector() -> EntryPointSelector; +} +impl GetValidateEntryPointSelector for DeclareTransaction { + fn get_validate_entry_point_selector() -> EntryPointSelector { + selector_from_name(blockifier::transaction::constants::VALIDATE_DECLARE_ENTRY_POINT_NAME) + } +} +impl GetValidateEntryPointSelector for DeployAccountTransaction { + fn get_validate_entry_point_selector() -> EntryPointSelector { + selector_from_name(blockifier::transaction::constants::VALIDATE_DEPLOY_ENTRY_POINT_NAME) + } +} +impl GetValidateEntryPointSelector for InvokeTransaction { + fn get_validate_entry_point_selector() -> EntryPointSelector { + selector_from_name(blockifier::transaction::constants::VALIDATE_ENTRY_POINT_NAME) + } +} +impl GetValidateEntryPointSelector for L1HandlerTransaction { + fn get_validate_entry_point_selector() -> EntryPointSelector { + selector_from_name(blockifier::transaction::constants::VALIDATE_ENTRY_POINT_NAME) + } +} + +pub trait Validate: GetValidateEntryPointSelector { + // Implement this to blacklist some transaction versions + fn validate_tx_version(&self) -> TransactionExecutionResult<()> { + Ok(()) + } + + fn validate( + &self, + state: &mut dyn State, + tx_context: Arc, + resources: &mut ExecutionResources, + remaining_gas: &mut u64, + validate_tx: bool, + charge_fee: bool, + strict_nonce_checking: bool, + ) -> TransactionExecutionResult>; + + fn perform_pre_validation_stage( + &self, + state: &mut dyn State, + tx_context: Arc, + strict_nonce_checking: bool, + charge_fee: bool, + ) -> TransactionExecutionResult<()>; + + fn run_validate_entrypoint( &self, state: &mut dyn State, - block_context: &BlockContext, + tx_context: Arc, + resources: &mut ExecutionResources, + remaining_gas: &mut u64, + limit_steps_by_resources: bool, + ) -> TransactionExecutionResult>; +} + +impl< + T: CheckFeeBounds + + GetValidateEntryPointCalldata + + HandleNonce + + GetValidateEntryPointSelector + + TransactionInfoCreator, +> Validate for T +{ + fn validate( + &self, + state: &mut dyn State, + tx_context: Arc, resources: &mut ExecutionResources, remaining_gas: &mut u64, validate_tx: bool, + charge_fee: bool, + strict_nonce_checking: bool, ) -> TransactionExecutionResult> { - let account_tx_context = self.get_account_transaction_context(validate_tx); - let mut context = EntryPointExecutionContext::new( - block_context.clone(), - account_tx_context, - block_context.invoke_tx_max_n_steps, - ); + // Check tx version, nonce and fee + self.perform_pre_validation_stage(state, tx_context.clone(), strict_nonce_checking, charge_fee)?; - self.validate_tx_inner(state, resources, remaining_gas, &mut context, self.calldata()) + // Run the actual `validate` entrypoint + if validate_tx { + self.run_validate_entrypoint(state, tx_context, resources, remaining_gas, charge_fee) + } else { + Ok(None) + } } - fn validate_tx_inner( + fn perform_pre_validation_stage( &self, state: &mut dyn State, + tx_context: Arc, + strict_nonce_checking: bool, + charge_fee: bool, + ) -> TransactionExecutionResult<()> { + // Check that version of the Tx is supported by the network + self.validate_tx_version()?; + + // Check if nonce has a correct value + Self::handle_nonce(state, &tx_context.tx_info, strict_nonce_checking)?; + + // Check if user has funds to pay the worst case scenario fees + if charge_fee && tx_context.tx_info.enforce_fee()? { + self.check_fee_bounds(&*tx_context)?; + + blockifier::fee::fee_utils::verify_can_pay_committed_bounds(state, &*tx_context)?; + } + + Ok(()) + } + + fn run_validate_entrypoint( + &self, + state: &mut dyn State, + tx_context: Arc, resources: &mut ExecutionResources, remaining_gas: &mut u64, - entry_point_execution_context: &mut EntryPointExecutionContext, - calldata: Calldata, + limit_steps_by_resources: bool, ) -> TransactionExecutionResult> { - if entry_point_execution_context.account_tx_context.is_v0() { + // Everything here is a copy paste from blockifier + // `impl ValidatableTransaction for AccountTransaction` + // in `crates/blockifier/src/transaction/account_transaction.rs` + let mut context = EntryPointExecutionContext::new_validate(tx_context, limit_steps_by_resources)?; + let tx_info = &context.tx_context.tx_info; + if tx_info.is_v0() { return Ok(None); } - let storage_address = entry_point_execution_context.account_tx_context.sender_address; + let storage_address = tx_info.sender_address(); + let validate_selector = Self::get_validate_entry_point_selector(); let validate_call = CallEntryPoint { entry_point_type: EntryPointType::External, - entry_point_selector: self.validate_entry_point_selector(), - calldata, + entry_point_selector: validate_selector, + calldata: self.get_validate_entry_point_calldata(), class_hash: None, code_address: None, storage_address, @@ -283,458 +448,411 @@ pub trait Validate: GetAccountTransactionContext + GetTransactionCalldata { initial_gas: *remaining_gas, }; - let validate_call_info = validate_call - .execute(state, resources, entry_point_execution_context) - .map_err(TransactionExecutionError::ValidateTransactionError)?; - verify_no_calls_to_other_contracts(&validate_call_info, String::from(VALIDATE_ENTRY_POINT_NAME))?; - update_remaining_gas(remaining_gas, &validate_call_info); + let validate_call_info = validate_call.execute(state, resources, &mut context).map_err(|error| { + TransactionExecutionError::ValidateTransactionError { error, storage_address, selector: validate_selector } + })?; + + // Validate return data. + let class_hash = state.get_class_hash_at(storage_address)?; + let contract_class = state.get_compiled_contract_class(class_hash)?; + if let ContractClass::V1(_) = contract_class { + // The account contract class is a Cairo 1.0 contract; the `validate` entry point should + // return `VALID`. + let expected_retdata = + Retdata(vec![StarkFelt::try_from(blockifier::transaction::constants::VALIDATE_RETDATA)?]); + if validate_call_info.execution.retdata != expected_retdata { + return Err(TransactionExecutionError::InvalidValidateReturnData { + actual: validate_call_info.execution.retdata, + }); + } + } + + blockifier::transaction::transaction_utils::update_remaining_gas(remaining_gas, &validate_call_info); Ok(Some(validate_call_info)) } } -pub trait Execute: Sized + GetAccountTransactionContext + GetTransactionCalldata + GetTxType { - fn execute_inner( - &self, - state: &mut S, - block_context: &BlockContext, - resources: &mut ExecutionResources, - remaining_gas: &mut u64, - account_tx_context: &AccountTransactionContext, - disable_validation: bool, - ) -> TransactionExecutionResult; +// Drop the cached state +// Write nothing to the actual storage +fn abort_transaction(transactional_state: CachedState>) {} - fn handle_nonce( - account_tx_context: &AccountTransactionContext, - state: &mut dyn State, - ) -> TransactionExecutionResult<()> { - if account_tx_context.version == TransactionVersion(StarkFelt::from(0_u8)) { - return Ok(()); - } +// TODO: +// This should be done in a substrate storage transaction to avoid some write failing at the end, +// leaving the storage in a half baked state. +// This should not happen if we use blockifier state adapter as its internal impl does not fail, but +// still we should respect the signature of those traits method. +// This probably will involve the creation of a `TransactionalBlockifierStateAdapter`. +fn commit_transaction( + transactional_state: CachedState>, +) -> StateResult<()> { + let storage_changes = transactional_state.get_actual_state_changes()?; - let address = account_tx_context.sender_address; - let current_nonce = state.get_nonce_at(address)?; - if current_nonce != account_tx_context.nonce { - return Err(TransactionExecutionError::InvalidNonce { - address, - expected_nonce: current_nonce, - actual_nonce: account_tx_context.nonce, - }); - } - - // Increment nonce. - state.increment_nonce(address)?; - - Ok(()) + // Because the nonce update is done inside `handle_nonce`, which is directly apply on the real + // storage, this seems to always be empty... + for (contract_address, nonce) in storage_changes.nonce_updates { + transactional_state.state.0.set_nonce_at(contract_address, nonce)?; } - /// Handles nonce and checks that the account's balance covers max fee. - fn handle_nonce_and_check_fee_balance( - state: &mut S, - block_context: &BlockContext, - account_tx_context: &AccountTransactionContext, - execution_config: &ExecutionConfig, - ) -> TransactionExecutionResult<()> { - // Handle nonce. - if !execution_config.disable_nonce_validation { - Self::handle_nonce(account_tx_context, state)?; - } - - // Check fee balance. Skipped in the following cases: - // 1. account_tx_context.max_fee - balance would always be enough if max_fee is 0 - // 2. disable_fee_charge - true during simulate transactions - // 3. disable_fee_charge - true when fees is disabled at app level - // 4. is_query - true during estimate_fee transactions. estimate_fee transactions normally have - // max_fee = 0 but they should also work if max_fee > 0 - if account_tx_context.max_fee != Fee(0) - && !execution_config.disable_fee_charge - && !execution_config.disable_transaction_fee - && !execution_config.is_query - { - log::debug!("Inside checking balance"); - let (balance_low, balance_high) = - state.get_fee_token_balance(block_context, &account_tx_context.sender_address)?; - - if balance_high <= StarkFelt::from(0_u8) && balance_low < StarkFelt::from(account_tx_context.max_fee.0) { - return Err(TransactionExecutionError::MaxFeeExceedsBalance { - max_fee: account_tx_context.max_fee, - balance_low, - balance_high, - }); - } - } - - Ok(()) + for (class_hash, compiled_class_hash) in storage_changes.compiled_class_hash_updates { + transactional_state.state.0.set_compiled_class_hash(class_hash, compiled_class_hash)?; } - fn execute( - &self, - state: &mut S, - block_context: &BlockContext, - execution_config: &ExecutionConfig, - ) -> TransactionExecutionResult { - let mut execution_resources = ExecutionResources::default(); - let mut remaining_gas = TX_INITIAL_AVAILABLE_GAS; - - let account_tx_context = self.get_account_transaction_context(execution_config.offset_version); + for (contract_address, class_hash) in storage_changes.class_hash_updates { + transactional_state.state.0.set_class_hash_at(contract_address, class_hash)?; + } - // Nonce and fee check should be done before running user code. - Self::handle_nonce_and_check_fee_balance(state, block_context, &account_tx_context, execution_config)?; + for (storage_enty, value) in storage_changes.storage_updates { + transactional_state.state.0.set_storage_at(storage_enty.0, storage_enty.1, value)?; + } - // execute - let ValidateExecuteCallInfo { validate_call_info, execute_call_info, revert_error } = self.execute_inner( - state, - block_context, - &mut execution_resources, - &mut remaining_gas, - &account_tx_context, - execution_config.disable_validation, - )?; + for (class_hash, contract_class) in transactional_state.class_hash_to_class.take() { + transactional_state.state.0.set_contract_class(class_hash, contract_class)?; + } - let (actual_fee, fee_transfer_call_info, actual_resources) = self.handle_fee( - state, - &execute_call_info, - &validate_call_info, - &mut execution_resources, - block_context, - account_tx_context, - execution_config, - )?; + Ok(()) +} - let tx_execution_info = TransactionExecutionInfo { - validate_call_info, - execute_call_info, - fee_transfer_call_info, - actual_fee, - actual_resources, - revert_error, - }; +pub trait SetArbitraryNonce: State { + fn set_nonce_at(&self, contract_address: ContractAddress, nonce: Nonce) -> StateResult<()>; +} - Ok(tx_execution_info) +impl<'a, S: State + SetArbitraryNonce> SetArbitraryNonce for MutRefState<'a, S> { + fn set_nonce_at(&self, contract_address: ContractAddress, nonce: Nonce) -> StateResult<()> { + self.0.set_nonce_at(contract_address, nonce) } +} - #[allow(clippy::too_many_arguments)] - fn handle_fee( - &self, - state: &mut S, - execute_call_info: &Option, - validate_call_info: &Option, - execution_resources: &mut ExecutionResources, - block_context: &BlockContext, - account_tx_context: AccountTransactionContext, - execution_config: &ExecutionConfig, - ) -> TransactionExecutionResult<(Fee, Option, ResourcesMapping)> { - let actual_resources = compute_transaction_resources( +pub fn run_non_revertible_transaction( + transaction: &T, + state: &mut S, + block_context: &BlockContext, + validate: bool, + charge_fee: bool, +) -> TransactionExecutionResult +where + S: State, + T: GetTxType + Executable + Validate + GetActualCostBuilder + TransactionInfoCreator, +{ + let mut resources = ExecutionResources::default(); + let mut remaining_gas = block_context.versioned_constants().tx_initial_gas(); + let tx_context = Arc::new(block_context.to_tx_context(transaction)); + + let validate_call_info: Option; + let execute_call_info: Option; + let strinct_nonce_checking = true; + if matches!(T::tx_type(), TransactionType::DeployAccount) { + // Handle `DeployAccount` transactions separately, due to different order of things. + // Also, the execution context required form the `DeployAccount` execute phase is + // validation context. + let mut execution_context = EntryPointExecutionContext::new_validate(tx_context.clone(), charge_fee)?; + execute_call_info = + transaction.run_execute(state, &mut resources, &mut execution_context, &mut remaining_gas)?; + validate_call_info = transaction.validate( state, - execute_call_info, - validate_call_info, - execution_resources, - Self::tx_type(), - None, + tx_context.clone(), + &mut resources, + &mut remaining_gas, + validate, + charge_fee, + strinct_nonce_checking, )?; - - let (actual_fee, fee_transfer_call_info) = charge_fee( + } else { + let mut execution_context = EntryPointExecutionContext::new_invoke(tx_context.clone(), charge_fee)?; + validate_call_info = transaction.validate( state, - block_context, - account_tx_context, - &actual_resources, - execution_config.disable_transaction_fee, - execution_config.disable_fee_charge, - execution_config.is_query, + tx_context.clone(), + &mut resources, + &mut remaining_gas, + validate, + charge_fee, + strinct_nonce_checking, )?; - - Ok((actual_fee, fee_transfer_call_info, actual_resources)) + execute_call_info = + transaction.run_execute(state, &mut resources, &mut execution_context, &mut remaining_gas)?; } -} -impl Validate for InvokeTransaction { - const VALIDATE_TX_ENTRY_POINT_NAME: &'static str = VALIDATE_ENTRY_POINT_NAME; -} + let (actual_cost, bouncer_resources) = transaction + .get_actual_cost_builder(tx_context.clone()) + .with_validate_call_info(&validate_call_info) + .with_execute_call_info(&execute_call_info) + .build(&resources)?; -impl Execute for InvokeTransaction { - fn execute_inner( - &self, - state: &mut S, - block_context: &BlockContext, - resources: &mut ExecutionResources, - remaining_gas: &mut u64, - account_tx_context: &AccountTransactionContext, - disable_validation: bool, - ) -> TransactionExecutionResult { - let mut context = EntryPointExecutionContext::new( - block_context.clone(), - account_tx_context.clone(), - block_context.invoke_tx_max_n_steps, + let post_execution_report = PostExecutionReport::new(state, &tx_context, &actual_cost, charge_fee)?; + let validate_execute_call_info = match post_execution_report.error() { + Some(error) => Err(TransactionExecutionError::from(error)), + None => Ok(ValidateExecuteCallInfo::new_accepted( + validate_call_info, + execute_call_info, + actual_cost, + bouncer_resources, + )), + }?; + + let fee_transfer_call_info = AccountTransaction::handle_fee( + state, + tx_context, + validate_execute_call_info.final_cost.actual_fee, + charge_fee, + )?; + + let tx_execution_info = TransactionExecutionInfo { + validate_call_info: validate_execute_call_info.validate_call_info, + execute_call_info: validate_execute_call_info.execute_call_info, + fee_transfer_call_info, + actual_fee: validate_execute_call_info.final_cost.actual_fee, + da_gas: validate_execute_call_info.final_cost.da_gas, + actual_resources: validate_execute_call_info.final_cost.actual_resources, + revert_error: validate_execute_call_info.revert_error, + bouncer_resources: validate_execute_call_info.bouncer_resources, + }; + + Ok(tx_execution_info) +} + +pub fn run_revertible_transaction( + transaction: &T, + state: &mut S, + block_context: &BlockContext, + validate: bool, + charge_fee: bool, +) -> TransactionExecutionResult +where + for<'a> T: Executable>> + + Validate + + GetActualCostBuilder + + GetTxType + + GetCalldataLen + + TransactionInfoCreator, + S: State + SetArbitraryNonce, +{ + let mut resources = ExecutionResources::default(); + let mut remaining_gas = block_context.versioned_constants().tx_initial_gas(); + let tx_context = Arc::new(block_context.to_tx_context(transaction)); + + let validate_call_info = transaction.validate( + state, + tx_context.clone(), + &mut resources, + &mut remaining_gas, + validate, + charge_fee, + true, + )?; + + let mut execution_context = EntryPointExecutionContext::new_invoke(tx_context.clone(), charge_fee)?; + + let n_allotted_execution_steps = execution_context.subtract_validation_and_overhead_steps( + &validate_call_info, + &T::tx_type(), + transaction.get_calldata_len(), + ); + + // Save the state changes resulting from running `validate_tx`, to be used later for + // resource and fee calculation. + let actual_cost_builder_with_validation_changes = + transaction.get_actual_cost_builder(tx_context.clone()).with_validate_call_info(&validate_call_info); + + let validate_execute_call_info = { + // Create copies of state and resources for the execution. + // Both will be rolled back if the execution is reverted or committed upon success. + let mut execution_resources = resources.clone(); + let mut transactional_state = CachedState::new(MutRefState::new(state), GlobalContractCache::new(10)); + + let execution_result = transaction.run_execute( + &mut transactional_state, + &mut execution_resources, + &mut execution_context, + &mut remaining_gas, ); - let validate_call_info = if !disable_validation { - self.validate_tx_inner( - state, - resources, - remaining_gas, - &mut context, - GetTransactionCalldata::calldata(self), - )? - } else { - None - }; - let validate_execute_call_info = match self.tx { - // V0 tx cannot revert, we cannot charge the failling ones - starknet_api::transaction::InvokeTransaction::V0(_) => { - let execute_call_info = self.run_execute(state, resources, &mut context, remaining_gas)?; - ValidateExecuteCallInfo::new_accepted(validate_call_info, execute_call_info) - } - starknet_api::transaction::InvokeTransaction::V1(_) => { - match self.run_execute(state, resources, &mut context, remaining_gas) { - Ok(execute_call_info) => { - ValidateExecuteCallInfo::new_accepted(validate_call_info, execute_call_info) + // Pre-compute cost in case of revert. + let execution_steps_consumed = n_allotted_execution_steps - execution_context.n_remaining_steps(); + let (revert_cost, bouncer_revert_resources) = actual_cost_builder_with_validation_changes + .clone() + .with_reverted_steps(execution_steps_consumed) + .build(&resources)?; + + match execution_result { + Ok(execute_call_info) => { + // When execution succeeded, calculate the actual required fee before committing the + // transactional state. If max_fee is insufficient, revert the `run_execute` part. + let (actual_cost, bouncer_resources) = actual_cost_builder_with_validation_changes + .with_execute_call_info(&execute_call_info) + // Fee is determined by the sum of `validate` and `execute` state changes. + // Since `execute_state_changes` are not yet committed, we merge them manually + // with `validate_state_changes` to count correctly. + .try_add_state_changes(&mut transactional_state)? + .build(&execution_resources)?; + + // Post-execution checks. + let post_execution_report = + PostExecutionReport::new(&transactional_state, &tx_context, &actual_cost, charge_fee)?; + match post_execution_report.error() { + Some(post_execution_error) => { + // Post-execution check failed. Revert the execution, compute the final fee + // to charge and recompute resources used (to be consistent with other + // revert case, compute resources by adding consumed execution steps to + // validation resources). + abort_transaction(transactional_state); + TransactionExecutionResult::Ok(ValidateExecuteCallInfo::new_reverted( + validate_call_info, + post_execution_error.to_string(), + ActualCost { actual_fee: post_execution_report.recommended_fee(), ..revert_cost }, + bouncer_revert_resources, + )) } - Err(e) => { - log::debug!("Invoke transaction reverted with error: {:?}", e); - ValidateExecuteCallInfo::new_reverted(validate_call_info, context.error_trace()) + None => { + // Post-execution check passed, commit the execution. + commit_transaction(transactional_state)?; + Ok(ValidateExecuteCallInfo::new_accepted( + validate_call_info, + execute_call_info, + actual_cost, + bouncer_resources, + )) } } } - }; - - Ok(validate_execute_call_info) - } -} - -impl Validate for DeclareTransaction { - const VALIDATE_TX_ENTRY_POINT_NAME: &'static str = VALIDATE_DECLARE_ENTRY_POINT_NAME; -} + Err(execution_error) => { + println!("REVERTING: {:?}", execution_error); + // Error during execution. Revert, even if the error is sequencer-related. + abort_transaction(transactional_state); + let post_execution_report = PostExecutionReport::new(state, &tx_context, &revert_cost, charge_fee)?; + TransactionExecutionResult::Ok(ValidateExecuteCallInfo::new_reverted( + validate_call_info, + execution_error.to_string(), + ActualCost { actual_fee: post_execution_report.recommended_fee(), ..revert_cost }, + bouncer_revert_resources, + )) + } + } + }?; -impl Execute for DeclareTransaction { - fn execute_inner( - &self, - state: &mut S, - block_context: &BlockContext, - resources: &mut ExecutionResources, - remaining_gas: &mut u64, - account_tx_context: &AccountTransactionContext, - disable_validation: bool, - ) -> TransactionExecutionResult { - let mut context = EntryPointExecutionContext::new( - block_context.clone(), - account_tx_context.clone(), - block_context.invoke_tx_max_n_steps, - ); + let fee_transfer_call_info = AccountTransaction::handle_fee( + state, + tx_context, + validate_execute_call_info.final_cost.actual_fee, + charge_fee, + )?; - let validate_call_info = if !disable_validation { - self.validate_tx_inner(state, resources, remaining_gas, &mut context, self.calldata())? - } else { - None - }; - let validate_execute_call_info = match self.tx() { - // V0 tx cannot revert, we cannot charge the failling ones - starknet_api::transaction::DeclareTransaction::V0(_) => { - let execute_call_info = self.run_execute(state, resources, &mut context, remaining_gas)?; - ValidateExecuteCallInfo::new_accepted(validate_call_info, execute_call_info) - } - starknet_api::transaction::DeclareTransaction::V1(_) - | starknet_api::transaction::DeclareTransaction::V2(_) => { - match self.run_execute(state, resources, &mut context, remaining_gas) { - Ok(execute_call_info) => { - ValidateExecuteCallInfo::new_accepted(validate_call_info, execute_call_info) - } - Err(_) => ValidateExecuteCallInfo::new_reverted(validate_call_info, context.error_trace()), - } - } - }; + let tx_execution_info = TransactionExecutionInfo { + validate_call_info: validate_execute_call_info.validate_call_info, + execute_call_info: validate_execute_call_info.execute_call_info, + fee_transfer_call_info, + actual_fee: validate_execute_call_info.final_cost.actual_fee, + da_gas: validate_execute_call_info.final_cost.da_gas, + actual_resources: validate_execute_call_info.final_cost.actual_resources, + revert_error: validate_execute_call_info.revert_error, + bouncer_resources: validate_execute_call_info.bouncer_resources, + }; - Ok(validate_execute_call_info) - } + Ok(tx_execution_info) } -impl Validate for DeployAccountTransaction { - const VALIDATE_TX_ENTRY_POINT_NAME: &'static str = VALIDATE_DEPLOY_ENTRY_POINT_NAME; -} +pub fn execute_l1_handler_transaction( + transaction: &L1HandlerTransaction, + state: &mut S, + block_context: &BlockContext, +) -> TransactionExecutionResult { + let mut execution_resources = ExecutionResources::default(); + let mut remaining_gas = block_context.versioned_constants().tx_initial_gas(); + let tx_context = Arc::new(block_context.to_tx_context(transaction)); -impl Execute for DeployAccountTransaction { - fn execute_inner( - &self, - state: &mut S, - block_context: &BlockContext, - resources: &mut ExecutionResources, - remaining_gas: &mut u64, - account_tx_context: &AccountTransactionContext, - disable_validation: bool, - ) -> TransactionExecutionResult { - let mut context = EntryPointExecutionContext::new( - block_context.clone(), - account_tx_context.clone(), - block_context.invoke_tx_max_n_steps, - ); + let mut context = EntryPointExecutionContext::new_invoke(tx_context.clone(), true)?; - // In order to be verified the tx must first be executed - // so that the `constructor` method can initialize the account state - let execute_call_info = self.run_execute(state, resources, &mut context, remaining_gas)?; - let validate_call_info = if !disable_validation { - self.validate_tx_inner(state, resources, remaining_gas, &mut context, self.calldata())? - } else { - None - }; + let execute_call_info = + transaction.run_execute(state, &mut execution_resources, &mut context, &mut remaining_gas)?; + let l1_handler_payload_size = transaction.payload_size(); + + let (ActualCost { actual_fee, da_gas, actual_resources }, _bouncer_resources) = + ActualCost::builder_for_l1_handler(tx_context, l1_handler_payload_size) + .with_execute_call_info(&execute_call_info) + .build(&execution_resources)?; - Ok(ValidateExecuteCallInfo::new_accepted(validate_call_info, execute_call_info)) + let paid_fee = transaction.paid_fee_on_l1; + // For now, assert only that any amount of fee was paid. + // The error message still indicates the required fee. + if paid_fee == Fee(0) { + return Err(TransactionFeeError::InsufficientL1Fee { paid_fee, actual_fee })?; } -} -impl Validate for L1HandlerTransaction { - const VALIDATE_TX_ENTRY_POINT_NAME: &'static str = VALIDATE_ENTRY_POINT_NAME; + Ok(TransactionExecutionInfo { + validate_call_info: None, + execute_call_info, + fee_transfer_call_info: None, + actual_fee: Fee::default(), + da_gas, + actual_resources: actual_resources.clone(), + revert_error: None, + bouncer_resources: actual_resources, + }) } -impl Execute for L1HandlerTransaction { - fn execute_inner( - &self, - state: &mut S, - block_context: &BlockContext, - resources: &mut ExecutionResources, - remaining_gas: &mut u64, - account_tx_context: &AccountTransactionContext, - _disable_validation: bool, - ) -> TransactionExecutionResult { - let mut context = EntryPointExecutionContext::new( - block_context.clone(), - account_tx_context.clone(), - block_context.invoke_tx_max_n_steps, - ); +/// Wraps a mutable reference to a `State` object, exposing its API. +/// Used to pass ownership to a `CachedState`. +pub struct MutRefState<'a, S: State + ?Sized>(&'a mut S); - let execute_call_info = self.run_execute(state, resources, &mut context, remaining_gas)?; +impl<'a, S: State + ?Sized> MutRefState<'a, S> { + pub fn new(state: &'a mut S) -> Self { + Self(state) + } +} - Ok(ValidateExecuteCallInfo::new_accepted(None, execute_call_info)) +/// Proxies inner object to expose `State` functionality. +impl<'a, S: State + ?Sized> StateReader for MutRefState<'a, S> { + fn get_storage_at(&self, contract_address: ContractAddress, key: StorageKey) -> StateResult { + self.0.get_storage_at(contract_address, key) } - // No fee are charged for L1HandlerTransaction - fn handle_fee( - &self, - state: &mut S, - execute_call_info: &Option, - validate_call_info: &Option, - execution_resources: &mut ExecutionResources, - block_context: &BlockContext, - _account_tx_context: AccountTransactionContext, - _execution_config: &ExecutionConfig, - ) -> TransactionExecutionResult<(Fee, Option, ResourcesMapping)> { - // The calldata includes the "from" field, which is not a part of the payload. - let l1_handler_payload_size = self.calldata().0.len() - 1; - - let actual_resources = compute_transaction_resources( - state, - execute_call_info, - validate_call_info, - execution_resources, - Self::tx_type(), - Some(l1_handler_payload_size), - )?; + fn get_nonce_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_nonce_at(contract_address) + } - let actual_fee = calculate_tx_fee(&actual_resources, block_context)?; + fn get_class_hash_at(&self, contract_address: ContractAddress) -> StateResult { + self.0.get_class_hash_at(contract_address) + } - let paid_fee = self.paid_fee_on_l1; - // For now, assert only that any amount of fee was paid. - // The error message still indicates the required fee. - if paid_fee == Fee(0) { - return Err(TransactionExecutionError::InsufficientL1Fee { paid_fee, actual_fee }); - } + fn get_compiled_contract_class(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_contract_class(class_hash) + } - Ok((Fee::default(), None, actual_resources)) + fn get_compiled_class_hash(&self, class_hash: ClassHash) -> StateResult { + self.0.get_compiled_class_hash(class_hash) } } -#[cfg(test)] -mod simulate_tx_offset { - use blockifier::execution::contract_class::ContractClass; - use starknet_ff::FieldElement; - - use super::*; - - #[test] - fn offset_is_correct() { - assert_eq!( - SIMULATE_TX_VERSION_OFFSET, - FieldElement::from_hex_be("0x100000000000000000000000000000000").unwrap() - ); +impl<'a, S: State + ?Sized> State for MutRefState<'a, S> { + fn set_storage_at( + &mut self, + contract_address: ContractAddress, + key: StorageKey, + value: StarkFelt, + ) -> StateResult<()> { + self.0.set_storage_at(contract_address, key, value) } - #[test] - fn l1_handler_transaction_correctly_applies_simulate_tx_version_offset() { - let l1_handler_tx = L1HandlerTransaction { - tx: Default::default(), - paid_fee_on_l1: Default::default(), - tx_hash: Default::default(), - }; - - let original_version = l1_handler_tx.tx.version; - let queried_version = l1_handler_tx.get_account_transaction_context(true).version; - - assert_eq!( - queried_version, - Felt252Wrapper(Felt252Wrapper::from(original_version.0).0 + SIMULATE_TX_VERSION_OFFSET).into() - ); - - let non_queried_version = l1_handler_tx.get_account_transaction_context(false).version; - assert_eq!(non_queried_version, original_version); + fn increment_nonce(&mut self, contract_address: ContractAddress) -> StateResult<()> { + self.0.increment_nonce(contract_address) } - #[test] - fn deploy_account_transaction_correctly_applies_simulate_tx_version_offset() { - let deploy_account_tx = DeployAccountTransaction { - tx: Default::default(), - tx_hash: Default::default(), - contract_address: Default::default(), - }; - - let original_version = deploy_account_tx.tx.version; - - let queried_version = deploy_account_tx.get_account_transaction_context(true).version; - assert_eq!( - queried_version, - Felt252Wrapper(Felt252Wrapper::from(original_version.0).0 + SIMULATE_TX_VERSION_OFFSET).into() - ); - - let non_queried_version = deploy_account_tx.get_account_transaction_context(false).version; - assert_eq!(non_queried_version, original_version); + fn set_class_hash_at(&mut self, contract_address: ContractAddress, class_hash: ClassHash) -> StateResult<()> { + self.0.set_class_hash_at(contract_address, class_hash) } - #[test] - fn declare_transaction_correctly_applies_simulate_tx_version_offset() { - let declare_tx_v0 = DeclareTransaction::new( - starknet_api::transaction::DeclareTransaction::V0(Default::default()), - Default::default(), - ContractClass::V0(Default::default()), - ) - .unwrap(); - - // gen TxVersion from v0 manually - let original_version_v0 = TransactionVersion(StarkFelt::from(0u8)); - - let queried_version = declare_tx_v0.get_account_transaction_context(true).version; - assert_eq!( - queried_version, - Felt252Wrapper(Felt252Wrapper::from(original_version_v0.0).0 + SIMULATE_TX_VERSION_OFFSET).into() - ); - - let non_queried_version = declare_tx_v0.get_account_transaction_context(false).version; - assert_eq!(non_queried_version, original_version_v0); + fn set_contract_class(&mut self, class_hash: ClassHash, contract_class: ContractClass) -> StateResult<()> { + self.0.set_contract_class(class_hash, contract_class) } - #[test] - fn invoke_transaction_correctly_applies_simulate_tx_version_offset() { - let invoke_tx = InvokeTransaction { - tx: starknet_api::transaction::InvokeTransaction::V0(Default::default()), - tx_hash: Default::default(), - }; - - // gen TxVersion from v0 manually - let original_version_v0 = TransactionVersion(StarkFelt::from(0u8)); - - let queried_version = invoke_tx.get_account_transaction_context(true).version; - assert_eq!( - queried_version, - Felt252Wrapper(Felt252Wrapper::from(original_version_v0.0).0 + SIMULATE_TX_VERSION_OFFSET).into() - ); + fn set_compiled_class_hash( + &mut self, + class_hash: ClassHash, + compiled_class_hash: CompiledClassHash, + ) -> StateResult<()> { + self.0.set_compiled_class_hash(class_hash, compiled_class_hash) + } - let non_queried_version = invoke_tx.get_account_transaction_context(false).version; - assert_eq!(non_queried_version, original_version_v0); + fn add_visited_pcs(&mut self, class_hash: ClassHash, pcs: &HashSet) { + self.0.add_visited_pcs(class_hash, pcs) } } diff --git a/crates/primitives/transactions/src/from_broadcasted_transactions.rs b/crates/primitives/transactions/src/from_broadcasted_transactions.rs index 51cdc2b09c..b6e647c333 100644 --- a/crates/primitives/transactions/src/from_broadcasted_transactions.rs +++ b/crates/primitives/transactions/src/from_broadcasted_transactions.rs @@ -1,34 +1,46 @@ use alloc::sync::Arc; -use std::collections::HashMap; -use blockifier::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV0Inner, ContractClassV1}; -use cairo_lang_casm_contract_class::{CasmContractClass, CasmContractEntryPoint, CasmContractEntryPoints}; -use cairo_lang_starknet::contract_class::{ +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, +}; +use cairo_lang_starknet_classes::contract_class::{ ContractClass as SierraContractClass, ContractEntryPoint, ContractEntryPoints, }; -use cairo_lang_starknet::contract_class_into_casm_contract_class::StarknetSierraCompilationError; use cairo_lang_utils::bigint::BigUintAsHex; use cairo_vm::types::program::Program; use flate2::read::GzDecoder; +use indexmap::IndexMap; use mp_felt::Felt252Wrapper; use num_bigint::{BigInt, BigUint, Sign}; -use starknet_api::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 { @@ -48,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( @@ -187,7 +264,7 @@ fn instantiate_blockifier_contract_class( let program: Program = Program::from_bytes(&program_decompressed_bytes, None) .map_err(|_| BroadcastedTransactionConversionError::ProgramDeserializationFailed)?; - let mut entry_points_by_type = >>::new(); + let mut entry_points_by_type = >>::new(); entry_points_by_type.insert( EntryPointType::Constructor, contract_class @@ -197,7 +274,7 @@ fn instantiate_blockifier_contract_class( .map(|entry_point| -> EntryPoint { EntryPoint { selector: EntryPointSelector(StarkFelt(entry_point.selector.to_bytes_be())), - offset: EntryPointOffset(entry_point.offset as usize), + offset: EntryPointOffset(entry_point.offset), } }) .collect::>(), @@ -211,7 +288,7 @@ fn instantiate_blockifier_contract_class( .map(|entry_point| -> EntryPoint { EntryPoint { selector: EntryPointSelector(StarkFelt(entry_point.selector.to_bytes_be())), - offset: EntryPointOffset(entry_point.offset as usize), + offset: EntryPointOffset(entry_point.offset), } }) .collect::>(), @@ -225,7 +302,7 @@ fn instantiate_blockifier_contract_class( .map(|entry_point| -> EntryPoint { EntryPoint { selector: EntryPointSelector(StarkFelt(entry_point.selector.to_bytes_be())), - offset: EntryPointOffset(entry_point.offset as usize), + offset: EntryPointOffset(entry_point.offset), } }) .collect::>(), @@ -262,7 +339,8 @@ fn flattened_sierra_to_casm_contract_class( ), abi: None, // we can convert the ABI but for now, to convert to Casm, the ABI isn't needed }; - let casm_contract_class = sierra_contract_class.into_casm_contract_class(false)?; + let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX)?; + Ok(casm_contract_class) } @@ -292,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() } @@ -304,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![], } } @@ -333,39 +413,164 @@ 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 }) + } + }) +} + +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, + }) + } + }) } -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) +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; @@ -411,7 +616,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] @@ -437,7 +642,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) ); } @@ -457,7 +662,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] @@ -477,7 +682,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/getters.rs b/crates/primitives/transactions/src/getters.rs index 4484fd61db..fce39ff361 100644 --- a/crates/primitives/transactions/src/getters.rs +++ b/crates/primitives/transactions/src/getters.rs @@ -4,8 +4,8 @@ use mp_felt::Felt252Wrapper; use super::{DeclareTransaction, DeployAccountTransaction, InvokeTransaction, Transaction, UserTransaction}; use crate::{ - DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, HandleL1MessageTransaction, InvokeTransactionV0, - InvokeTransactionV1, UserOrL1HandlerTransaction, + DeclareTransactionV0, DeclareTransactionV1, DeclareTransactionV2, HandleL1MessageTransaction, InvokeTransactionV1, + UserOrL1HandlerTransaction, }; impl Transaction { @@ -52,10 +52,10 @@ impl UserTransaction { } } - pub fn nonce(&self) -> Option<&Felt252Wrapper> { + pub fn nonce(&self) -> &Felt252Wrapper { match self { - UserTransaction::Declare(tx, _) => Some(tx.nonce()), - UserTransaction::DeployAccount(tx) => Some(tx.nonce()), + UserTransaction::Declare(tx, _) => tx.nonce(), + UserTransaction::DeployAccount(tx) => tx.nonce(), UserTransaction::Invoke(tx) => tx.nonce(), } } @@ -67,6 +67,14 @@ impl UserTransaction { UserTransaction::Invoke(tx) => tx.offset_version(), } } + + pub fn version(&self) -> u8 { + match self { + UserTransaction::Declare(tx, _) => tx.version(), + UserTransaction::DeployAccount(tx) => tx.version(), + UserTransaction::Invoke(tx) => tx.version(), + } + } } impl DeclareTransaction { @@ -161,43 +169,36 @@ impl DeployAccountTransaction { impl InvokeTransaction { pub fn sender_address(&self) -> &Felt252Wrapper { match self { - InvokeTransaction::V0(tx) => &tx.contract_address, InvokeTransaction::V1(tx) => &tx.sender_address, } } pub fn signature(&self) -> &Vec { match self { - InvokeTransaction::V0(tx) => &tx.signature, InvokeTransaction::V1(tx) => &tx.signature, } } pub fn max_fee(&self) -> &u128 { match self { - InvokeTransaction::V0(tx) => &tx.max_fee, InvokeTransaction::V1(tx) => &tx.max_fee, } } pub fn calldata(&self) -> &Vec { match self { - InvokeTransaction::V0(tx) => &tx.calldata, InvokeTransaction::V1(tx) => &tx.calldata, } } - pub fn nonce(&self) -> Option<&Felt252Wrapper> { + pub fn nonce(&self) -> &Felt252Wrapper { match self { - InvokeTransaction::V0(_) => None, - InvokeTransaction::V1(tx) => Some(&tx.nonce), + InvokeTransaction::V1(tx) => &tx.nonce, } } pub fn offset_version(&self) -> bool { match self { - // we don't accept V0 txs from the RPC - InvokeTransaction::V0(_) => false, InvokeTransaction::V1(tx) => tx.offset_version, } } @@ -244,19 +245,11 @@ impl TransactionVersion for InvokeTransaction { #[inline(always)] fn version(&self) -> u8 { match self { - InvokeTransaction::V0(tx) => tx.version(), InvokeTransaction::V1(tx) => tx.version(), } } } -impl TransactionVersion for InvokeTransactionV0 { - #[inline(always)] - fn version(&self) -> u8 { - 0 - } -} - impl TransactionVersion for InvokeTransactionV1 { #[inline(always)] fn version(&self) -> u8 { diff --git a/crates/primitives/transactions/src/lib.rs b/crates/primitives/transactions/src/lib.rs index fe1b7023c4..d447743c0d 100644 --- a/crates/primitives/transactions/src/lib.rs +++ b/crates/primitives/transactions/src/lib.rs @@ -1,26 +1,29 @@ //! Starknet transaction related functionality. -#![cfg_attr(not(feature = "std"), no_std)] +#![feature(trait_upcasting)] #[doc(hidden)] pub extern crate alloc; pub mod compute_hash; -pub mod conversions; pub mod execution; +// pub mod conversions; #[cfg(feature = "client")] pub mod from_broadcasted_transactions; -pub mod getters; +// pub mod getters; #[cfg(feature = "client")] pub mod to_starknet_core_transaction; -#[cfg(feature = "client")] -pub mod utils; +// #[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; @@ -38,6 +41,21 @@ pub struct TransactionStatus { pub execution_status: TransactionExecutionStatus, } +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. @@ -56,172 +74,199 @@ pub enum TxType { L1Handler, } -impl From for TransactionType { - fn from(value: TxType) -> Self { - match value { - TxType::Invoke => TransactionType::InvokeFunction, - TxType::Declare => TransactionType::Declare, - TxType::DeployAccount => TransactionType::DeployAccount, - TxType::L1Handler => TransactionType::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<&UserTransaction> for TxType { - fn from(value: &UserTransaction) -> Self { +// impl From for TransactionType { +// fn from(value: TxType) -> Self { +// match value { +// TxType::Invoke => TransactionType::InvokeFunction, +// TxType::Declare => TransactionType::Declare, +// TxType::DeployAccount => TransactionType::DeployAccount, +// TxType::L1Handler => TransactionType::L1Handler, +// } +// } +// } + +impl From<&AccountTransaction> for TxType { + fn from(value: &AccountTransaction) -> Self { match value { - UserTransaction::Declare(_, _) => TxType::Declare, - UserTransaction::DeployAccount(_) => TxType::DeployAccount, - UserTransaction::Invoke(_) => TxType::Invoke, + AccountTransaction::Declare(_) => TxType::Declare, + AccountTransaction::DeployAccount(_) => TxType::DeployAccount, + AccountTransaction::Invoke(_) => TxType::Invoke, } } } -impl From<&UserOrL1HandlerTransaction> for TxType { - fn from(value: &UserOrL1HandlerTransaction) -> Self { +impl From<&Transaction> for TxType { + fn from(value: &Transaction) -> Self { match value { - UserOrL1HandlerTransaction::User(tx) => tx.into(), - UserOrL1HandlerTransaction::L1Handler(_, _) => TxType::L1Handler, + 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, parity_scale_codec::Decode))] -#[cfg_attr(feature = "scale-info", derive(scale_info::TypeInfo))] -pub enum UserTransaction { - Declare(DeclareTransaction, ContractClass), - DeployAccount(DeployAccountTransaction), - Invoke(InvokeTransaction), -} - -#[derive(Clone, Debug, Eq, PartialEq, From)] -#[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 Transaction { - Declare(DeclareTransaction, ContractClass), - DeployAccount(DeployAccountTransaction), - Invoke(InvokeTransaction), - L1Handler(HandleL1MessageTransaction), -} +// #[derive(Clone, Debug, Eq, PartialEq, From)] +// #[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 UserTransaction { +// Declare(DeclareTransaction, ContractClass), +// DeployAccount(DeployAccountTransaction), +// Invoke(InvokeTransaction), +// } -#[derive(Clone, Debug, Eq, PartialEq, From)] -#[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 UserOrL1HandlerTransaction { - User(UserTransaction), - L1Handler(HandleL1MessageTransaction, Fee), -} +// #[derive(Clone, Debug, Eq, PartialEq, From)] +// #[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 Transaction { +// Declare(DeclareTransaction, ContractClass), +// DeployAccount(DeployAccountTransaction), +// Invoke(InvokeTransaction), +// L1Handler(HandleL1MessageTransaction), +// } -#[derive(Debug, Clone, Eq, PartialEq, From)] -#[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 InvokeTransaction { - V0(InvokeTransactionV0), - V1(InvokeTransactionV1), -} +// #[derive(Clone, Debug, Eq, PartialEq, From)] +// #[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 UserOrL1HandlerTransaction { +// User(UserTransaction), +// L1Handler(HandleL1MessageTransaction, Fee), +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct InvokeTransactionV0 { - pub max_fee: u128, - pub signature: Vec, - pub contract_address: Felt252Wrapper, - pub entry_point_selector: Felt252Wrapper, - pub calldata: Vec, -} +// #[derive(Debug, Clone, Eq, PartialEq, From)] +// #[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 InvokeTransaction { +// V1(InvokeTransactionV1), +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct InvokeTransactionV1 { - pub max_fee: u128, - pub signature: Vec, - pub nonce: Felt252Wrapper, - pub sender_address: Felt252Wrapper, - pub calldata: Vec, - pub offset_version: bool, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct InvokeTransactionV1 { +// pub max_fee: u128, +// pub signature: Vec, +// pub nonce: Felt252Wrapper, +// pub sender_address: Felt252Wrapper, +// pub calldata: Vec, +// pub offset_version: bool, +// } -#[derive(Debug, Clone, Eq, PartialEq, From)] -#[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 DeclareTransaction { - V0(DeclareTransactionV0), - V1(DeclareTransactionV1), - V2(DeclareTransactionV2), -} +// #[derive(Debug, Clone, Eq, PartialEq, From)] +// #[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 DeclareTransaction { +// V0(DeclareTransactionV0), +// V1(DeclareTransactionV1), +// V2(DeclareTransactionV2), +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct DeclareTransactionV0 { - pub max_fee: u128, - pub signature: Vec, - pub nonce: Felt252Wrapper, - pub class_hash: Felt252Wrapper, - pub sender_address: Felt252Wrapper, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct DeclareTransactionV0 { +// pub max_fee: u128, +// pub signature: Vec, +// pub nonce: Felt252Wrapper, +// pub class_hash: Felt252Wrapper, +// pub sender_address: Felt252Wrapper, +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct DeclareTransactionV1 { - pub max_fee: u128, - pub signature: Vec, - pub nonce: Felt252Wrapper, - pub class_hash: Felt252Wrapper, - pub sender_address: Felt252Wrapper, - pub offset_version: bool, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct DeclareTransactionV1 { +// pub max_fee: u128, +// pub signature: Vec, +// pub nonce: Felt252Wrapper, +// pub class_hash: Felt252Wrapper, +// pub sender_address: Felt252Wrapper, +// pub offset_version: bool, +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct DeclareTransactionV2 { - pub max_fee: u128, - pub signature: Vec, - pub nonce: Felt252Wrapper, - pub class_hash: Felt252Wrapper, - pub sender_address: Felt252Wrapper, - pub compiled_class_hash: Felt252Wrapper, - pub offset_version: bool, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct DeclareTransactionV2 { +// pub max_fee: u128, +// pub signature: Vec, +// pub nonce: Felt252Wrapper, +// pub class_hash: Felt252Wrapper, +// pub sender_address: Felt252Wrapper, +// pub compiled_class_hash: Felt252Wrapper, +// pub offset_version: bool, +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct DeployAccountTransaction { - pub max_fee: u128, - pub signature: Vec, - pub nonce: Felt252Wrapper, - pub contract_address_salt: Felt252Wrapper, - pub constructor_calldata: Vec, - pub class_hash: Felt252Wrapper, - pub offset_version: bool, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct DeployAccountTransaction { +// pub max_fee: u128, +// pub signature: Vec, +// pub nonce: Felt252Wrapper, +// pub contract_address_salt: Felt252Wrapper, +// pub constructor_calldata: Vec, +// pub class_hash: Felt252Wrapper, +// pub offset_version: bool, +// } -#[derive(Debug, Clone, Eq, PartialEq)] -#[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 struct HandleL1MessageTransaction { - pub nonce: u64, - pub contract_address: Felt252Wrapper, - pub entry_point_selector: Felt252Wrapper, - pub calldata: Vec, -} +// #[derive(Debug, Clone, Eq, PartialEq)] +// #[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 struct HandleL1MessageTransaction { +// pub nonce: u64, +// pub contract_address: Felt252Wrapper, +// pub entry_point_selector: Felt252Wrapper, +// pub calldata: Vec, +// } -impl From for HandleL1MessageTransaction { - fn from(msg: MsgFromL1) -> Self { - let calldata = - std::iter::once(msg.from_address.into()).chain(msg.payload.into_iter().map(|felt| felt.into())).collect(); +// impl From for HandleL1MessageTransaction { +// fn from(msg: MsgFromL1) -> Self { +// let calldata = +// std::iter::once(msg.from_address.into()).chain(msg.payload.into_iter().map(|felt| +// felt.into())).collect(); - Self { - contract_address: msg.to_address.into(), - nonce: 0u32.into(), - entry_point_selector: msg.entry_point_selector.into(), - calldata, - } - } -} +// Self { +// contract_address: msg.to_address.into(), +// nonce: 0u32.into(), +// entry_point_selector: msg.entry_point_selector.into(), +// calldata, +// } +// } +// } diff --git a/crates/primitives/transactions/src/to_starknet_core_transaction.rs b/crates/primitives/transactions/src/to_starknet_core_transaction.rs index 5ddc27128f..191f9a5649 100644 --- a/crates/primitives/transactions/src/to_starknet_core_transaction.rs +++ b/crates/primitives/transactions/src/to_starknet_core_transaction.rs @@ -1,148 +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::V0(super::InvokeTransactionV0 { - max_fee, - signature, - contract_address, - entry_point_selector, - calldata, - }) => starknet_core::types::InvokeTransaction::V0(starknet_core::types::InvokeTransactionV0 { - transaction_hash, - max_fee: max_fee.into(), - signature: cast_vec_of_felt_252_wrappers(signature), - contract_address: contract_address.into(), - entry_point_selector: entry_point_selector.into(), - calldata: cast_vec_of_felt_252_wrappers(calldata), - }), - 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/primitives/transactions/src/utils.rs b/crates/primitives/transactions/src/utils.rs index c80694aed0..62eb2859b3 100644 --- a/crates/primitives/transactions/src/utils.rs +++ b/crates/primitives/transactions/src/utils.rs @@ -1,8 +1,7 @@ -use cairo_lang_casm_contract_class::CasmContractClass; -use cairo_lang_starknet::contract_class::{ +use cairo_lang_starknet_classes::casm_contract_class::{CasmContractClass, StarknetSierraCompilationError}; +use cairo_lang_starknet_classes::contract_class::{ ContractClass as SierraContractClass, ContractEntryPoint, ContractEntryPoints, }; -use cairo_lang_starknet::contract_class_into_casm_contract_class::StarknetSierraCompilationError; use cairo_lang_utils::bigint::BigUintAsHex; use num_bigint::BigUint; @@ -18,7 +17,7 @@ pub fn sierra_to_casm_contract_class( ) -> Result { let sierra_contract_entry_points = ContractEntryPoints { external: contract_class - .entry_point_by_type + .entry_points_by_type .get(&starknet_api::state::EntryPointType::External) .cloned() .unwrap_or_default() @@ -26,7 +25,7 @@ pub fn sierra_to_casm_contract_class( .map(starknet_api_entry_point_to_contract_entry_point) .collect(), constructor: contract_class - .entry_point_by_type + .entry_points_by_type .get(&starknet_api::state::EntryPointType::Constructor) .cloned() .unwrap_or_default() @@ -34,7 +33,7 @@ pub fn sierra_to_casm_contract_class( .map(starknet_api_entry_point_to_contract_entry_point) .collect(), l1_handler: contract_class - .entry_point_by_type + .entry_points_by_type .get(&starknet_api::state::EntryPointType::L1Handler) .cloned() .unwrap_or_default() @@ -54,7 +53,8 @@ pub fn sierra_to_casm_contract_class( entry_points_by_type: sierra_contract_entry_points, abi: None, // we can convert the ABI but for now, to convert to Casm, the ABI isn't needed }; - let casm_contract_class = sierra_contract_class.into_casm_contract_class(false)?; + + let casm_contract_class = CasmContractClass::from_contract_class(sierra_contract_class, false, usize::MAX)?; Ok(casm_contract_class) } diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index d1f02d968d..49cff9ff19 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -102,8 +102,6 @@ std = [ # 3rd party dependencies "parity-scale-codec/std", "scale-info/std", - "blockifier/std", - "starknet_api/std", ] try-runtime = [ "pallet-timestamp/try-runtime", diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs index 8d827560f6..8ca54d82b7 100644 --- a/crates/runtime/src/lib.rs +++ b/crates/runtime/src/lib.rs @@ -17,9 +17,13 @@ mod pallets; mod runtime_tests; mod types; +use blockifier::context::FeeTokenAddresses; use blockifier::execution::contract_class::ContractClass; use blockifier::state::cached_state::CommitmentStateDiff; +use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::objects::TransactionExecutionInfo; +use blockifier::transaction::transaction_execution::Transaction; +use blockifier::transaction::transactions::L1HandlerTransaction; pub use config::*; pub use frame_support::traits::{ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, Randomness, StorageInfo}; pub use frame_support::weights::constants::{ @@ -30,8 +34,6 @@ pub use frame_support::{construct_runtime, parameter_types, StorageValue}; pub use frame_system::Call as SystemCall; use mp_felt::Felt252Wrapper; use mp_simulations::{PlaceHolderErrorTypeForFailedStarknetExecution, SimulationFlags, TransactionSimulationResult}; -use mp_transactions::compute_hash::ComputeTransactionHash; -use mp_transactions::{HandleL1MessageTransaction, Transaction, UserOrL1HandlerTransaction, UserTransaction}; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; /// Import the Starknet pallet. pub use pallet_starknet; @@ -51,10 +53,10 @@ use sp_runtime::{generic, ApplyExtrinsicResult, DispatchError}; pub use sp_runtime::{Perbill, Permill}; use sp_std::prelude::*; use sp_version::RuntimeVersion; -use starknet_api::api_core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::StorageKey; -use starknet_api::transaction::{Calldata, Event as StarknetEvent, Fee, MessageToL1, TransactionHash}; +use starknet_api::transaction::{Calldata, Event as StarknetEvent, MessageToL1, TransactionHash}; /// Import the types. pub use types::*; @@ -248,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 { @@ -267,62 +269,62 @@ impl_runtime_apis! { Starknet::config_hash() } - fn fee_token_address() -> ContractAddress { - Starknet::fee_token_address() + fn fee_token_addresses() -> FeeTokenAddresses { + Starknet::fee_token_addresses() } fn is_transaction_fee_disabled() -> bool { Starknet::is_transaction_fee_disabled() } - fn estimate_fee(transactions: Vec) -> Result, DispatchError> { + fn estimate_fee(transactions: Vec) -> Result, DispatchError> { Starknet::estimate_fee(transactions) } - fn re_execute_transactions(transactions: Vec) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError> { + fn re_execute_transactions(transactions: Vec) -> Result, PlaceHolderErrorTypeForFailedStarknetExecution>, DispatchError> { Starknet::re_execute_transactions(transactions) } - fn estimate_message_fee(message: HandleL1MessageTransaction) -> Result<(u128, u64, u64), DispatchError> { + fn estimate_message_fee(message: L1HandlerTransaction) -> Result<(u128, u128, u128), DispatchError> { Starknet::estimate_message_fee(message) } - fn simulate_transactions(transactions: Vec, simulation_flags: SimulationFlags) -> Result, DispatchError> { + fn simulate_transactions(transactions: Vec, simulation_flags: SimulationFlags) -> Result, DispatchError> { Starknet::simulate_transactions(transactions, &simulation_flags) } - fn simulate_message(message: HandleL1MessageTransaction, simulation_flags: SimulationFlags) -> Result, DispatchError> { + fn simulate_message(message: L1HandlerTransaction, simulation_flags: SimulationFlags) -> Result, DispatchError> { Starknet::simulate_message(message, &simulation_flags) } fn extrinsic_filter(xts: Vec<::Extrinsic>) -> Vec { xts.into_iter().filter_map(|xt| match xt.function { - RuntimeCall::Starknet( invoke { transaction }) => Some(Transaction::Invoke(transaction)), - RuntimeCall::Starknet( declare { transaction, contract_class }) => Some(Transaction::Declare(transaction, contract_class)), - RuntimeCall::Starknet( deploy_account { transaction }) => Some(Transaction::DeployAccount(transaction)), - RuntimeCall::Starknet( consume_l1_message { transaction, .. }) => Some(Transaction::L1Handler(transaction)), - _ => None + RuntimeCall::Starknet( invoke { transaction }) => Some(Transaction::AccountTransaction(AccountTransaction::Invoke(transaction))), + RuntimeCall::Starknet( declare { transaction }) => Some(Transaction::AccountTransaction(AccountTransaction::Declare(transaction))), + RuntimeCall::Starknet( deploy_account { transaction }) => Some(Transaction::AccountTransaction(AccountTransaction::DeployAccount(transaction))), + RuntimeCall::Starknet( consume_l1_message { transaction }) => Some(Transaction::L1HandlerTransaction(transaction)), + _ => None, }).collect::>() } - fn get_index_and_tx_for_tx_hash(extrinsics: Vec<::Extrinsic>, chain_id: Felt252Wrapper, tx_hash: Felt252Wrapper) -> 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 { - RuntimeCall::Starknet( invoke { transaction }) => transaction.compute_hash::<::SystemHash>(chain_id, false), - RuntimeCall::Starknet( declare { transaction, .. }) => transaction.compute_hash::<::SystemHash>(chain_id, false), - RuntimeCall::Starknet( deploy_account { transaction }) => transaction.compute_hash::<::SystemHash>(chain_id, false), - RuntimeCall::Starknet( consume_l1_message { transaction, .. }) => transaction.compute_hash::<::SystemHash>(chain_id, false), + RuntimeCall::Starknet( invoke { transaction }) => transaction.tx_hash, + RuntimeCall::Starknet( declare { transaction, .. }) => transaction.tx_hash, + RuntimeCall::Starknet( deploy_account { transaction }) => transaction.tx_hash, + RuntimeCall::Starknet( consume_l1_message { transaction, .. }) => transaction.tx_hash, _ => return false }; computed_tx_hash == tx_hash })?; let transaction = match tx.function { - RuntimeCall::Starknet( invoke { transaction }) => Transaction::Invoke(transaction), - RuntimeCall::Starknet( declare { transaction, contract_class }) => Transaction::Declare(transaction, contract_class), - RuntimeCall::Starknet( deploy_account { transaction }) => Transaction::DeployAccount(transaction), - RuntimeCall::Starknet( consume_l1_message { transaction, .. }) => Transaction::L1Handler(transaction), + RuntimeCall::Starknet( invoke { transaction }) => Transaction::AccountTransaction(AccountTransaction::Invoke(transaction)), + RuntimeCall::Starknet( declare { transaction }) => Transaction::AccountTransaction(AccountTransaction::Declare(transaction)), + RuntimeCall::Starknet( deploy_account { transaction }) => Transaction::AccountTransaction(AccountTransaction::DeployAccount(transaction)), + RuntimeCall::Starknet( consume_l1_message { transaction }) => Transaction::L1HandlerTransaction(transaction), _ => unreachable!("The previous match made sure that at this point tx is one of those starknet calls"), }; @@ -342,7 +344,7 @@ impl_runtime_apis! { Starknet::tx_revert_error(tx_hash).map(|s| s.into_bytes()) } - fn get_block_context() -> pallet_starknet_runtime_api::BlockContext { + fn get_block_context() -> blockifier::context::BlockContext { Starknet::get_block_context().into() } @@ -352,15 +354,15 @@ impl_runtime_apis! { } impl pallet_starknet_runtime_api::ConvertTransactionRuntimeApi for Runtime { - fn convert_transaction(transaction: UserTransaction) -> UncheckedExtrinsic { + fn convert_transaction(transaction: AccountTransaction) -> UncheckedExtrinsic { let call = match transaction { - UserTransaction::Declare(tx, contract_class) => { - pallet_starknet::Call::declare { transaction: tx, contract_class } + AccountTransaction::Declare(tx) => { + pallet_starknet::Call::declare { transaction: tx } } - UserTransaction::DeployAccount(tx) => { + AccountTransaction::DeployAccount(tx) => { pallet_starknet::Call::deploy_account { transaction: tx } } - UserTransaction::Invoke(tx) => { + AccountTransaction::Invoke(tx) => { pallet_starknet::Call::invoke { transaction: tx } } }; @@ -368,8 +370,8 @@ impl_runtime_apis! { UncheckedExtrinsic::new_unsigned(call.into()) } - fn convert_l1_transaction(transaction: HandleL1MessageTransaction, fee: Fee) -> UncheckedExtrinsic { - let call = pallet_starknet::Call::::consume_l1_message { transaction, paid_fee_on_l1: fee }; + fn convert_l1_transaction(transaction: L1HandlerTransaction) -> UncheckedExtrinsic { + let call = pallet_starknet::Call::::consume_l1_message { transaction }; UncheckedExtrinsic::new_unsigned(call.into()) } diff --git a/crates/runtime/src/pallets.rs b/crates/runtime/src/pallets.rs index cb0dc50b64..637ea51140 100644 --- a/crates/runtime/src/pallets.rs +++ b/crates/runtime/src/pallets.rs @@ -1,6 +1,9 @@ //! Configuration of the pallets used in the runtime. //! The pallets used in the runtime are configured here. //! This file is used to generate the `construct_runtime!` macro. +use std::num::NonZeroU128; + +use blockifier::blockifier::block::GasPrices; pub use frame_support::traits::{ ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, KeyOwnerProofSystem, OnTimestampSet, Randomness, StorageInfo, }; @@ -11,7 +14,6 @@ pub use frame_support::weights::{IdentityFee, Weight}; pub use frame_support::{construct_runtime, parameter_types, StorageValue}; pub use frame_system::Call as SystemCall; pub use mp_chain_id::SN_GOERLI_CHAIN_ID; -use mp_fee::ResourcePrice; pub use mp_program_hash::SN_OS_PROGRAM_HASH; /// Import the StarkNet pallet. pub use pallet_starknet; @@ -48,7 +50,7 @@ impl pallet_starknet::Config for Runtime { type ChainId = ChainId; type MaxRecursionDepth = MaxRecursionDepth; type ProgramHash = ProgramHash; - type L1GasPrice = L1GasPrice; + type L1GasPrices = L1GasPrices; } /// -------------------------------------- @@ -163,7 +165,7 @@ parameter_types! { pub const ChainId: Felt252Wrapper = SN_GOERLI_CHAIN_ID; pub const MaxRecursionDepth: u32 = 50; pub const ProgramHash: Felt252Wrapper = SN_OS_PROGRAM_HASH; - pub const L1GasPrice: ResourcePrice = ResourcePrice { price_in_strk: None, price_in_wei: 10 }; + pub const L1GasPrices: GasPrices = GasPrices { eth_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, eth_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) }, strk_l1_data_gas_price: unsafe { NonZeroU128::new_unchecked(10) } }; } /// Implement the OnTimestampSet trait to override the default Aura. diff --git a/starknet-e2e-test/ethereum_core_contract.rs b/starknet-e2e-test/ethereum_core_contract.rs index a19683d5f5..e155622932 100644 --- a/starknet-e2e-test/ethereum_core_contract.rs +++ b/starknet-e2e-test/ethereum_core_contract.rs @@ -6,7 +6,7 @@ use mc_settlement::{SettlementProvider, StarknetSpec, StarknetState}; use mp_messages::{MessageL1ToL2, MessageL2ToL1}; use mp_snos_output::StarknetOsOutput; use rstest::rstest; -use starknet_api::api_core::{ContractAddress, Nonce, PatriciaKey}; +use starknet_api::core::{ContractAddress, EntryPointSelector, Nonce, PatriciaKey}; use starknet_api::hash::StarkFelt; use starknet_e2e_test::starknet_sovereign::StarknetSovereign; @@ -68,7 +68,7 @@ async fn starknet_core_contract_sends_messages_to_l2() -> anyhow::Result<()> { from_address: ContractAddress(PatriciaKey(StarkFelt::new(from_address).unwrap())), to_address: 3u64.into(), nonce: Nonce(0u64.into()), // Starknet contract maintains global nonce counter - selector: 2u64.into(), + selector: EntryPointSelector(StarkFelt::from(2u64)), payload: vec![1u64.into()], }; diff --git a/starknet-e2e-test/src/starknet_sovereign.rs b/starknet-e2e-test/src/starknet_sovereign.rs index 6b868ac5b1..75508bc132 100644 --- a/starknet-e2e-test/src/starknet_sovereign.rs +++ b/starknet-e2e-test/src/starknet_sovereign.rs @@ -151,7 +151,7 @@ impl StarknetSovereign { self.client .send_message_to_l2( convert_felt_to_u256(message.to_address.0.0), - convert_felt_to_u256(message.selector), + convert_felt_to_u256(message.selector.0), message.payload.clone().into_iter().map(convert_felt_to_u256).collect(), 1.into(), ) diff --git a/starknet-rpc-test/Cargo.toml b/starknet-rpc-test/Cargo.toml index 7f8a294a94..078c470618 100644 --- a/starknet-rpc-test/Cargo.toml +++ b/starknet-rpc-test/Cargo.toml @@ -30,98 +30,98 @@ url = "2.4.1" # name = "starknet_spec_version" # path = "spec_version.rs" -[[test]] -name = "starknet_get_block_number" -path = "get_block_number.rs" +# [[test]] +# name = "starknet_get_block_number" +# path = "get_block_number.rs" -[[test]] -name = "starknet_get_block_hash_and_number" -path = "get_block_hash_and_number.rs" +# [[test]] +# name = "starknet_get_block_hash_and_number" +# path = "get_block_hash_and_number.rs" -[[test]] -name = "starknet_get_block_transaction_count" -path = "get_block_transaction_count.rs" +# [[test]] +# name = "starknet_get_block_transaction_count" +# path = "get_block_transaction_count.rs" -[[test]] -name = "starknet_chain_id" -path = "chain_id.rs" +# [[test]] +# name = "starknet_chain_id" +# path = "chain_id.rs" -[[test]] -name = "starknet_get_storage_at" -path = "get_storage_at.rs" +# [[test]] +# name = "starknet_get_storage_at" +# path = "get_storage_at.rs" -[[test]] -name = "starknet_get_class" -path = "get_class.rs" +# [[test]] +# name = "starknet_get_class" +# path = "get_class.rs" -[[test]] -name = "starknet_get_class_at" -path = "get_class_at.rs" +# [[test]] +# name = "starknet_get_class_at" +# path = "get_class_at.rs" -[[test]] -name = "starknet_get_class_hash_at" -path = "get_class_hash_at.rs" +# [[test]] +# name = "starknet_get_class_hash_at" +# path = "get_class_hash_at.rs" -[[test]] -name = "starknet_get_nonce" -path = "get_nonce.rs" +# [[test]] +# name = "starknet_get_nonce" +# path = "get_nonce.rs" -[[test]] -name = "starknet_call" -path = "call.rs" +# [[test]] +# name = "starknet_call" +# path = "call.rs" -[[test]] -name = "starknet_get_block_with_tx_hashes" -path = "get_block_with_tx_hashes.rs" +# [[test]] +# name = "starknet_get_block_with_tx_hashes" +# path = "get_block_with_tx_hashes.rs" -[[test]] -name = "starknet_get_block_with_txs" -path = "get_block_with_txs.rs" +# [[test]] +# name = "starknet_get_block_with_txs" +# path = "get_block_with_txs.rs" -[[test]] -name = "starknet_get_transaction_by_blockid_and_index" -path = "get_transaction_by_blockid_and_index.rs" +# [[test]] +# name = "starknet_get_transaction_by_blockid_and_index" +# path = "get_transaction_by_blockid_and_index.rs" [[test]] name = "starknet_add_invoke_transaction" path = "add_invoke_transaction.rs" -[[test]] -name = "starknet_add_declare_transaction" -path = "add_declare_transaction.rs" +# [[test]] +# name = "starknet_add_declare_transaction" +# path = "add_declare_transaction.rs" -[[test]] -name = "starknet_add_deploy_account_transaction" -path = "add_deploy_account_transaction.rs" +# [[test]] +# name = "starknet_add_deploy_account_transaction" +# path = "add_deploy_account_transaction.rs" -[[test]] -name = "starknet_get_transaction_by_hash" -path = "get_transaction_by_hash.rs" +# [[test]] +# name = "starknet_get_transaction_by_hash" +# path = "get_transaction_by_hash.rs" -[[test]] -name = "starknet_get_transaction_receipt" -path = "get_transaction_receipt.rs" +# [[test]] +# name = "starknet_get_transaction_receipt" +# path = "get_transaction_receipt.rs" -[[test]] -name = "starknet_get_events" -path = "get_events.rs" +# [[test]] +# name = "starknet_get_events" +# path = "get_events.rs" -[[test]] -name = "starknet_estimate_fee" -path = "estimate_fee.rs" +# [[test]] +# name = "starknet_estimate_fee" +# path = "estimate_fee.rs" -[[test]] -name = "starknet_estimate_message_fee" -path = "estimate_message_fee.rs" +# [[test]] +# name = "starknet_estimate_message_fee" +# path = "estimate_message_fee.rs" -[[test]] -name = "starknet_simulate_transaction" -path = "simulate_transaction.rs" +# [[test]] +# name = "starknet_simulate_transaction" +# path = "simulate_transaction.rs" -[[test]] -name = "starknet_get_state_update" -path = "get_state_update.rs" +# [[test]] +# name = "starknet_get_state_update" +# path = "get_state_update.rs" -[[test]] -name = "starknet_trace_block_transactions" -path = "trace_block.rs" +# [[test]] +# name = "starknet_trace_block_transactions" +# path = "trace_block.rs" diff --git a/starknet-rpc-test/add_declare_transaction.rs b/starknet-rpc-test/add_declare_transaction.rs index 44cf2134d1..4cf209467b 100644 --- a/starknet-rpc-test/add_declare_transaction.rs +++ b/starknet-rpc-test/add_declare_transaction.rs @@ -7,8 +7,10 @@ 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_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, OZ_CONTRACT_ADDRESS, SIGNER_PRIVATE}; +use starknet_providers::{Provider, ProviderError}; +use starknet_rpc_test::constants::{ + ARGENT_CONTRACT_ADDRESS, ETH_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}; use starknet_rpc_test::{SendTransactionError, Transaction, TransactionResult}; @@ -35,10 +37,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(_) ))) ); @@ -60,18 +59,28 @@ async fn fail_execution_step_with_no_storage_change(madara: &ThreadSafeMadaraCli let mut madara_write_lock = madara.write().await; // draining oz_account so the txn fails during execution let balance = - read_erc20_balance(&rpc, FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), oz_account.address()).await; + read_erc20_balance(&rpc, FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), oz_account.address()) + .await; + println!("{:?}", balance); madara_write_lock .create_block_with_txs(vec![Transaction::Execution(oz_account.transfer_tokens_u256( FieldElement::from_hex_be(ARGENT_CONTRACT_ADDRESS).unwrap(), // subtractin 150k to keep some fees for the transfer - U256 { low: balance[0] - FieldElement::from_dec_str("150000").unwrap(), high: balance[1] }, + U256 { low: balance[0] - FieldElement::from(1_000_000u128), high: balance[1] }, None, ))]) .await?; + let balance = + read_erc20_balance(&rpc, FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), oz_account.address()) + .await; + println!("{:?}", balance); // declaring contract let txs = madara_write_lock.create_block_with_txs(vec![Transaction::Declaration(declare_tx)]).await?; + let balance = + read_erc20_balance(&rpc, FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), oz_account.address()) + .await; + println!("{:?}", balance); let block_number = rpc.block_number().await?; (block_number, txs) }; @@ -156,10 +165,7 @@ async fn fails_already_declared(madara: &ThreadSafeMadaraClient) -> Result<(), a assert_matches!( declare_tx_result.err(), Some(SendTransactionError::AccountError(starknet_accounts::AccountError::Provider( - ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ClassAlreadyDeclared), - message: _ - }) + ProviderError::StarknetError(StarknetError::ClassAlreadyDeclared) ))) ); diff --git a/starknet-rpc-test/add_invoke_transaction.rs b/starknet-rpc-test/add_invoke_transaction.rs index 44bad6fe78..8b7584ad29 100644 --- a/starknet-rpc-test/add_invoke_transaction.rs +++ b/starknet-rpc-test/add_invoke_transaction.rs @@ -7,8 +7,8 @@ use rstest::rstest; use starknet_accounts::Account; use starknet_core::types::{BlockId, StarknetError}; use starknet_ff::FieldElement; -use starknet_providers::{MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; -use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, SIGNER_PRIVATE}; +use starknet_providers::{Provider, ProviderError}; +use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, ETH_FEE_TOKEN_ADDRESS, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, read_erc20_balance, AccountActions, U256}; use starknet_rpc_test::{SendTransactionError, Transaction}; @@ -38,10 +38,7 @@ async fn fail_validation_step(madara: &ThreadSafeMadaraClient) -> Result<(), any assert_matches!( invoke_tx_result, SendTransactionError::AccountError(starknet_accounts::AccountError::Provider(ProviderError::StarknetError( - StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::ValidationFailure), - message: _ - } + StarknetError::ValidationFailure(_) ))) ); @@ -56,7 +53,7 @@ async fn works_with_storage_change(madara: &ThreadSafeMadaraClient) -> Result<() let funding_account = build_single_owner_account(&rpc, SIGNER_PRIVATE, ARGENT_CONTRACT_ADDRESS, true); let recipient_account = FieldElement::from_hex_be("0x123").unwrap(); - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); let (txs, initial_balance, final_balance, block_number) = { let mut madara_write_lock = madara.write().await; let initial_balance = read_erc20_balance(&rpc, fee_token_address, recipient_account).await; @@ -96,7 +93,7 @@ async fn fail_execution_step_with_no_storage_change(madara: &ThreadSafeMadaraCli let rpc = madara.get_starknet_client().await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); let funding_account = build_single_owner_account(&rpc, SIGNER_PRIVATE, ARGENT_CONTRACT_ADDRESS, true); diff --git a/starknet-rpc-test/call.rs b/starknet-rpc-test/call.rs index f54b160835..8c909ef28e 100644 --- a/starknet-rpc-test/call.rs +++ b/starknet-rpc-test/call.rs @@ -12,8 +12,8 @@ use starknet_contract::ContractFactory; use starknet_core::types::{BlockId, BlockTag, FunctionCall, StarknetError}; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; -use starknet_providers::{MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; -use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, SIGNER_PRIVATE}; +use starknet_providers::{Provider, ProviderError}; +use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, ETH_FEE_TOKEN_ADDRESS, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, get_contract_address_from_deploy_tx, AccountActions}; use starknet_rpc_test::Transaction; @@ -26,7 +26,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.call( FunctionCall { - contract_address: FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + contract_address: FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), entry_point_selector: get_selector_from_name("name").unwrap(), calldata: vec![] }, @@ -34,10 +34,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), ) .await .err(), - Some(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::BlockNotFound) - })) + Some(ProviderError::StarknetError(StarknetError::BlockNotFound)) ); Ok(()) @@ -51,7 +48,7 @@ async fn fail_non_existing_entrypoint(madara: &ThreadSafeMadaraClient) -> Result assert_matches!( rpc.call( FunctionCall { - contract_address: FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + contract_address: FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), entry_point_selector: FieldElement::from_hex_be("0x0").unwrap(), calldata: vec![] }, @@ -59,10 +56,7 @@ async fn fail_non_existing_entrypoint(madara: &ThreadSafeMadaraClient) -> Result ) .await .err(), - Some(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::ContractError) - })) + Some(ProviderError::StarknetError(StarknetError::ContractError(_))) ); Ok(()) @@ -76,7 +70,7 @@ async fn fail_incorrect_calldata(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.call( FunctionCall { - contract_address: FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + contract_address: FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), entry_point_selector: get_selector_from_name("name").unwrap(), calldata: vec![FieldElement::ONE] // name function has no calldata }, @@ -84,10 +78,7 @@ async fn fail_incorrect_calldata(madara: &ThreadSafeMadaraClient) -> Result<(), ) .await .err(), - Some(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::ContractError) - })) + Some(ProviderError::StarknetError(StarknetError::ContractError(_))) ); Ok(()) @@ -101,7 +92,7 @@ async fn works_on_correct_call_no_calldata(madara: &ThreadSafeMadaraClient) -> R assert_eq!( rpc.call( FunctionCall { - contract_address: FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + contract_address: FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), entry_point_selector: get_selector_from_name("name").unwrap(), calldata: vec![] // name function has no calldata }, @@ -123,7 +114,7 @@ async fn works_on_correct_call_with_calldata(madara: &ThreadSafeMadaraClient) -> assert!( rpc.call( FunctionCall { - contract_address: FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + contract_address: FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), entry_point_selector: get_selector_from_name("balanceOf").unwrap(), calldata: vec![FieldElement::TWO] // name function has no calldata }, diff --git a/starknet-rpc-test/estimate_fee.rs b/starknet-rpc-test/estimate_fee.rs index 897246c12a..568ee58f72 100644 --- a/starknet-rpc-test/estimate_fee.rs +++ b/starknet-rpc-test/estimate_fee.rs @@ -2,11 +2,14 @@ extern crate starknet_rpc_test; use assert_matches::assert_matches; use rstest::rstest; -use starknet_core::types::{BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedTransaction, StarknetError}; +use starknet_core::types::{ + BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction, + StarknetError, +}; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{ACCOUNT_CONTRACT, TEST_CONTRACT_ADDRESS}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; @@ -15,23 +18,24 @@ use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let ok_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::ZERO, - signature: vec![], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), - calldata: vec![ - FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), - get_selector_from_name("sqrt").unwrap(), - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from(81u8), - ], - is_query: true, - }); + let ok_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::ZERO, + signature: vec![], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), + calldata: vec![ + FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), + get_selector_from_name("sqrt").unwrap(), + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from(81u8), + ], + is_query: true, + })); 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], vec![], BlockId::Hash(FieldElement::ZERO)).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -42,35 +46,35 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), async fn fail_if_one_txn_cannot_be_executed(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let bad_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::default(), - nonce: FieldElement::ZERO, - sender_address: FieldElement::default(), - signature: vec![], - calldata: vec![FieldElement::from_hex_be("0x0").unwrap()], - is_query: true, - }); - - let ok_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::ZERO, - signature: vec![], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), - calldata: vec![ - FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), - get_selector_from_name("sqrt").unwrap(), - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from(81u8), - ], - is_query: true, - }); + let bad_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::default(), + nonce: FieldElement::ZERO, + sender_address: FieldElement::default(), + signature: vec![], + calldata: vec![FieldElement::from_hex_be("0x0").unwrap()], + is_query: true, + })); + + let ok_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::ZERO, + signature: vec![], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), + calldata: vec![ + FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), + get_selector_from_name("sqrt").unwrap(), + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from(81u8), + ], + is_query: true, + })); assert_matches!( - rpc.estimate_fee(&vec![ - bad_invoke_transaction, - ok_invoke_transaction, - ], BlockId::Tag(BlockTag::Latest)).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractError + rpc.estimate_fee(&vec![bad_invoke_transaction, ok_invoke_transaction,], vec![], BlockId::Tag(BlockTag::Latest)) + .await, + Err(StarknetProviderError(StarknetError::ContractError(_))) ); Ok(()) @@ -81,7 +85,7 @@ async fn fail_if_one_txn_cannot_be_executed(madara: &ThreadSafeMadaraClient) -> async fn works_ok(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let tx = BroadcastedInvokeTransaction { + let tx = BroadcastedInvokeTransactionV1 { max_fee: FieldElement::ZERO, signature: vec![], nonce: FieldElement::ZERO, @@ -95,21 +99,25 @@ async fn works_ok(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> is_query: true, }; - let invoke_transaction = BroadcastedTransaction::Invoke(tx.clone()); + let invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(tx.clone())); let invoke_transaction_2 = - BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { nonce: FieldElement::ONE, ..tx }); + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + nonce: FieldElement::ONE, + ..tx + })); - let estimates = - rpc.estimate_fee(&vec![invoke_transaction, invoke_transaction_2], BlockId::Tag(BlockTag::Latest)).await?; + let estimates = rpc + .estimate_fee(&vec![invoke_transaction, invoke_transaction_2], vec![], BlockId::Tag(BlockTag::Latest)) + .await?; // TODO: instead execute the tx and check that the actual fee are the same as the estimated ones assert_eq!(estimates.len(), 2); - assert_eq!(estimates[0].overall_fee, 210); - assert_eq!(estimates[1].overall_fee, 210); + assert_eq!(estimates[0].overall_fee, FieldElement::from(210u128)); + assert_eq!(estimates[1].overall_fee, FieldElement::from(210u128)); // https://starkscan.co/block/5 - assert_eq!(estimates[0].gas_consumed, 0); - assert_eq!(estimates[1].gas_consumed, 0); + assert_eq!(estimates[0].gas_consumed, FieldElement::ZERO); + assert_eq!(estimates[1].gas_consumed, FieldElement::ZERO); Ok(()) } diff --git a/starknet-rpc-test/estimate_message_fee.rs b/starknet-rpc-test/estimate_message_fee.rs index e252ac140d..2b0a13a380 100644 --- a/starknet-rpc-test/estimate_message_fee.rs +++ b/starknet-rpc-test/estimate_message_fee.rs @@ -5,8 +5,8 @@ use rstest::rstest; use starknet_core::types::{BlockId, BlockTag, EthAddress, MsgFromL1, StarknetError}; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{L1_CONTRACT_ADDRESS, TEST_CONTRACT_ADDRESS}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; @@ -24,8 +24,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.estimate_message_fee(message, BlockId::Hash(FieldElement::ZERO)).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: -MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound ); + Err(StarknetProviderError(StarknetError::BlockNotFound)) + ); Ok(()) } @@ -44,8 +44,8 @@ async fn fail_if_message_fail(madara: &ThreadSafeMadaraClient) -> Result<(), any assert_matches!( rpc.estimate_message_fee(message, BlockId::Tag(BlockTag::Latest)).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: -MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractError ); + Err(StarknetProviderError(StarknetError::ContractError(_))) + ); Ok(()) } @@ -67,9 +67,9 @@ async fn works_ok(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> let fee = rpc.estimate_message_fee(message, BlockId::Tag(BlockTag::Latest)).await?; - assert_eq!(fee.gas_consumed, 17091); - assert_eq!(fee.gas_price, 10); - assert_eq!(fee.overall_fee, 0); + assert_eq!(fee.gas_consumed, FieldElement::from(17091u128)); + assert_eq!(fee.gas_price, FieldElement::from(10u128)); + assert_eq!(fee.overall_fee, FieldElement::ZERO); Ok(()) } diff --git a/starknet-rpc-test/get_block_with_tx_hashes.rs b/starknet-rpc-test/get_block_with_tx_hashes.rs index f2c461c347..5cfdf0c356 100644 --- a/starknet-rpc-test/get_block_with_tx_hashes.rs +++ b/starknet-rpc-test/get_block_with_tx_hashes.rs @@ -8,7 +8,7 @@ use anyhow::anyhow; use rstest::rstest; use starknet_core::types::{BlockId, BlockTag, MaybePendingBlockWithTxHashes, 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, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; @@ -21,10 +21,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.get_block_with_tx_hashes(BlockId::Hash(FieldElement::ZERO)).await.err(), - Some(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::BlockNotFound) - })) + Some(ProviderError::StarknetError(StarknetError::BlockNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_block_with_txs.rs b/starknet-rpc-test/get_block_with_txs.rs index 67b5524eff..ad2d9de5bc 100644 --- a/starknet-rpc-test/get_block_with_txs.rs +++ b/starknet-rpc-test/get_block_with_txs.rs @@ -8,14 +8,15 @@ use anyhow::anyhow; use rstest::rstest; use starknet_accounts::Account; use starknet_core::types::{ - BlockId, BlockStatus, BlockTag, DeclareTransaction, InvokeTransaction, MaybePendingBlockWithTxs, StarknetError, - Transaction as StarknetTransaction, + BlockId, BlockStatus, BlockTag, DeclareTransaction, DeployAccountTransaction, InvokeTransaction, + MaybePendingBlockWithTxs, StarknetError, Transaction as StarknetTransaction, }; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; -use starknet_providers::{MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; +use starknet_providers::{Provider, ProviderError}; use starknet_rpc_test::constants::{ - ARGENT_CONTRACT_ADDRESS, CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, FEE_TOKEN_ADDRESS, MAX_FEE_OVERRIDE, SIGNER_PRIVATE, + ARGENT_CONTRACT_ADDRESS, CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, ETH_FEE_TOKEN_ADDRESS, MAX_FEE_OVERRIDE, + SIGNER_PRIVATE, }; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{ @@ -30,10 +31,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.get_block_with_txs(BlockId::Hash(FieldElement::ZERO)).await.err(), - Some(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::BlockNotFound) - })) + Some(ProviderError::StarknetError(StarknetError::BlockNotFound)) ); Ok(()) @@ -78,7 +76,7 @@ async fn works_with_invoke_txn(madara: &ThreadSafeMadaraClient) -> Result<(), an tx.calldata, vec![ FieldElement::ONE, - FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), get_selector_from_name("transfer").unwrap(), FieldElement::ZERO, FieldElement::THREE, @@ -132,7 +130,7 @@ async fn works_with_pending_invoke_txn(madara: &ThreadSafeMadaraClient) -> Resul tx.calldata, vec![ FieldElement::ONE, - FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), + FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), get_selector_from_name("transfer").unwrap(), FieldElement::ZERO, FieldElement::THREE, @@ -183,7 +181,7 @@ async fn works_with_deploy_account_txn(madara: &ThreadSafeMadaraClient) -> Resul assert_eq!(block.transactions.len(), 1); let tx = match &block.transactions[0] { - StarknetTransaction::DeployAccount(tx) => tx, + StarknetTransaction::DeployAccount(DeployAccountTransaction::V1(tx)) => tx, _ => return Err(anyhow!("Expected an deploy transaction v1")), }; assert_eq!(tx.nonce, 0u8.into()); @@ -241,16 +239,16 @@ async fn works_with_pending_deploy_account_txn(madara: &ThreadSafeMadaraClient) }; assert_eq!(pending_block.transactions.len(), 1); - let tx = match &pending_block.transactions[0] { - StarknetTransaction::DeployAccount(tx) => tx, + let transaction = match &pending_block.transactions[0] { + StarknetTransaction::DeployAccount(DeployAccountTransaction::V1(tx)) => tx, _ => return Err(anyhow!("Expected an deploy transaction v1")), }; - assert_eq!(tx.nonce, 0u8.into()); - assert_eq!(tx.max_fee, max_fee); - assert_eq!(tx.contract_address_salt, contract_address_salt); - assert_eq!(tx.class_hash, class_hash); + assert_eq!(transaction.nonce, 0u8.into()); + assert_eq!(transaction.max_fee, max_fee); + assert_eq!(transaction.contract_address_salt, contract_address_salt); + assert_eq!(transaction.class_hash, class_hash); assert_eq!( - tx.constructor_calldata, + transaction.constructor_calldata, vec![FieldElement::from_hex_be("0x047de619de131463cbf799d321b50c617566dc897d4be614fb3927eacd55d7ad").unwrap()] ); diff --git a/starknet-rpc-test/get_class.rs b/starknet-rpc-test/get_class.rs index 1f623c2cc7..b7482036e3 100644 --- a/starknet-rpc-test/get_class.rs +++ b/starknet-rpc-test/get_class.rs @@ -9,8 +9,8 @@ use starknet_core::types::contract::legacy::{LegacyContractClass, LegacyProgram} use starknet_core::types::contract::SierraClass; use starknet_core::types::{BlockId, ContractClass, FlattenedSierraClass, StarknetError}; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, TEST_CONTRACT_CLASS_HASH}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; @@ -23,13 +23,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), FieldElement::from_hex_be(TEST_CONTRACT_CLASS_HASH).expect("Invalid Contract Address"); assert_matches!( - rpc - .get_class( - BlockId::Number(100), - test_contract_class_hash, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.get_class(BlockId::Number(100), test_contract_class_hash,).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -44,13 +39,8 @@ async fn fail_non_existing_class_hash(madara: &ThreadSafeMadaraClient) -> Result FieldElement::from_hex_be("0x4269DEADBEEF").expect("Invalid Contract classh hash"); assert_matches!( - rpc - .get_class( - BlockId::Number(0), - unknown_contract_class_hash, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ClassHashNotFound + rpc.get_class(BlockId::Number(0), unknown_contract_class_hash,).await, + Err(StarknetProviderError(StarknetError::ClassHashNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_class_at.rs b/starknet-rpc-test/get_class_at.rs index dbb7890e32..1eee8a2413 100644 --- a/starknet-rpc-test/get_class_at.rs +++ b/starknet-rpc-test/get_class_at.rs @@ -9,8 +9,8 @@ use starknet_core::types::contract::legacy::{LegacyContractClass, LegacyProgram} use starknet_core::types::contract::SierraClass; use starknet_core::types::{BlockId, ContractClass, FlattenedSierraClass, StarknetError}; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{CAIRO_1_ACCOUNT_CONTRACT, TEST_CONTRACT_ADDRESS}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; @@ -22,13 +22,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), let test_contract_address = FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).expect("Invalid Contract Address"); assert_matches!( - rpc - .get_class_at( - BlockId::Number(100), - test_contract_address, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.get_class_at(BlockId::Number(100), test_contract_address,).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -42,13 +37,8 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( let unknown_contract_address = FieldElement::from_hex_be("0x4269DEADBEEF").expect("Invalid Contract Address"); assert_matches!( - rpc - .get_class_at( - BlockId::Number(0), - unknown_contract_address, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractNotFound + rpc.get_class_at(BlockId::Number(0), unknown_contract_address,).await, + Err(StarknetProviderError(StarknetError::ContractNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_class_hash_at.rs b/starknet-rpc-test/get_class_hash_at.rs index e5e25d13d2..2421d8416f 100644 --- a/starknet-rpc-test/get_class_hash_at.rs +++ b/starknet-rpc-test/get_class_hash_at.rs @@ -4,8 +4,8 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_core::types::{BlockId, StarknetError}; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{TEST_CONTRACT_ADDRESS, TEST_CONTRACT_CLASS_HASH}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; @@ -17,13 +17,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), let test_contract_address = FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).expect("Invalid Contract Address"); assert_matches!( - rpc - .get_class_hash_at( - BlockId::Number(100), - test_contract_address, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.get_class_hash_at(BlockId::Number(100), test_contract_address,).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -37,13 +32,8 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( let unknown_contract_address = FieldElement::from_hex_be("0x4269DEADBEEF").expect("Invalid Contract Address"); assert_matches!( - rpc - .get_class_hash_at( - BlockId::Number(0), - unknown_contract_address, - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractNotFound + rpc.get_class_hash_at(BlockId::Number(0), unknown_contract_address,).await, + Err(StarknetProviderError(StarknetError::ContractNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_events.rs b/starknet-rpc-test/get_events.rs index fadcae923e..09630fe3c0 100644 --- a/starknet-rpc-test/get_events.rs +++ b/starknet-rpc-test/get_events.rs @@ -7,8 +7,8 @@ use starknet_core::types::{BlockId, EmittedEvent, EventFilter, StarknetError}; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; use starknet_providers::jsonrpc::HttpTransport; -use starknet_providers::{JsonRpcClient, MaybeUnknownErrorCode, Provider, ProviderError, StarknetErrorWithMessage}; -use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, SEQUENCER_ADDRESS, SIGNER_PRIVATE}; +use starknet_providers::{JsonRpcClient, Provider, ProviderError}; +use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, ETH_FEE_TOKEN_ADDRESS, SEQUENCER_ADDRESS, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; use starknet_rpc_test::{MadaraClient, Transaction, TransactionResult}; @@ -50,13 +50,7 @@ async fn fail_invalid_continuation_token(madara: &ThreadSafeMadaraClient) -> Res ) .await; - assert_matches!( - events_result, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::InvalidContinuationToken) - })) - ); + assert_matches!(events_result, Err(ProviderError::StarknetError(StarknetError::InvalidContinuationToken))); Ok(()) } @@ -79,13 +73,7 @@ async fn fail_chunk_size_too_big(madara: &ThreadSafeMadaraClient) -> Result<(), ) .await; - assert_matches!( - events_result, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::PageSizeTooBig) - })) - ); + assert_matches!(events_result, Err(ProviderError::StarknetError(StarknetError::PageSizeTooBig))); Ok(()) } @@ -108,13 +96,7 @@ async fn fail_keys_too_big(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow ) .await; - assert_matches!( - events_result, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - message: _, - code: MaybeUnknownErrorCode::Known(StarknetError::TooManyKeysInFilter) - })) - ); + assert_matches!(events_result, Err(ProviderError::StarknetError(StarknetError::TooManyKeysInFilter))); Ok(()) } @@ -137,7 +119,7 @@ async fn work_one_block_no_filter(madara: &ThreadSafeMadaraClient) -> Result<(), .await .unwrap(); - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); let block_hash = FieldElement::from_hex_be("0x0742520489186d3d79b09e1d14ec7e69d515a3c915e6cfd8fd4ca65299372a45").unwrap(); let expected_fee = FieldElement::from_hex_be("0x1d010").unwrap(); @@ -154,8 +136,8 @@ async fn work_one_block_no_filter(madara: &ThreadSafeMadaraClient) -> Result<(), transfer_amount, // value low FieldElement::ZERO, // value high ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, }, EmittedEvent { @@ -167,8 +149,8 @@ async fn work_one_block_no_filter(madara: &ThreadSafeMadaraClient) -> Result<(), FieldElement::ONE, FieldElement::ONE, ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, }, EmittedEvent { @@ -180,8 +162,8 @@ async fn work_one_block_no_filter(madara: &ThreadSafeMadaraClient) -> Result<(), expected_fee, // value low FieldElement::ZERO, // value high ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, }, ] @@ -209,7 +191,7 @@ async fn work_one_block_with_chunk_filter_and_continuation_token( .await .unwrap(); - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); let block_hash = FieldElement::from_hex_be("0x0742520489186d3d79b09e1d14ec7e69d515a3c915e6cfd8fd4ca65299372a45").unwrap(); @@ -236,8 +218,8 @@ async fn work_one_block_with_chunk_filter_and_continuation_token( FieldElement::ONE, FieldElement::ONE, ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, }, EmittedEvent { @@ -249,8 +231,8 @@ async fn work_one_block_with_chunk_filter_and_continuation_token( expected_fee, // value low FieldElement::ZERO, // value high ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, }, ] @@ -293,7 +275,7 @@ async fn work_two_blocks_with_block_filter_and_continuation_token( .await .unwrap(); - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); assert_eq!( events_result.events, @@ -306,8 +288,8 @@ async fn work_two_blocks_with_block_filter_and_continuation_token( transfer_amount, // value low FieldElement::ZERO, // value high ], - block_hash: first_block_number_and_hash.block_hash, - block_number: first_block_number_and_hash.block_number, + block_hash: Some(first_block_number_and_hash.block_hash), + block_number: Some(first_block_number_and_hash.block_number), transaction_hash: transaction_hash_1, }], ); @@ -339,8 +321,8 @@ async fn work_two_blocks_with_block_filter_and_continuation_token( transfer_amount, // value low FieldElement::ZERO, // value high ], - block_hash: second_block_number_and_hash.block_hash, - block_number: second_block_number_and_hash.block_number, + block_hash: Some(second_block_number_and_hash.block_hash), + block_number: Some(second_block_number_and_hash.block_number), transaction_hash: transaction_hash_2, }], ); @@ -384,8 +366,8 @@ async fn work_one_block_address_filter(madara: &ThreadSafeMadaraClient) -> Resul FieldElement::ONE, FieldElement::ONE, ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, } }); @@ -430,8 +412,8 @@ async fn work_one_block_key_filter(madara: &ThreadSafeMadaraClient) -> Result<() FieldElement::ONE, FieldElement::ONE, ], - block_hash, - block_number, + block_hash: Some(block_hash), + block_number: Some(block_number), transaction_hash, } }); diff --git a/starknet-rpc-test/get_nonce.rs b/starknet-rpc-test/get_nonce.rs index 4550ec4c44..02aa516366 100644 --- a/starknet-rpc-test/get_nonce.rs +++ b/starknet-rpc-test/get_nonce.rs @@ -8,7 +8,7 @@ use rstest::rstest; use starknet_accounts::Account; use starknet_core::types::{BlockId, BlockTag, 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, CONTRACT_ADDRESS, MINT_AMOUNT, SIGNER_PRIVATE, TEST_CONTRACT_ADDRESS, }; @@ -22,13 +22,12 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), let rpc = madara.get_starknet_client().await; assert_matches!( - rpc - .get_nonce( + rpc.get_nonce( BlockId::Hash(FieldElement::ZERO), FieldElement::from_hex_be(CONTRACT_ADDRESS).expect("Invalid Contract Address"), ) .await, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + Err(ProviderError::StarknetError(StarknetError::BlockNotFound)) ); Ok(()) @@ -40,13 +39,12 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( let rpc = madara.get_starknet_client().await; assert_matches!( - rpc - .get_nonce( + rpc.get_nonce( BlockId::Tag(BlockTag::Latest), FieldElement::from_hex_be("0x51e59c2c182a58fb0a74349bfa4769cbbcba32547591dd3fb1def8623997d00").unwrap(), ) .await, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractNotFound + Err(ProviderError::StarknetError(StarknetError::ContractNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_state_update.rs b/starknet-rpc-test/get_state_update.rs index ed5f15fa14..d54beeb2a3 100644 --- a/starknet-rpc-test/get_state_update.rs +++ b/starknet-rpc-test/get_state_update.rs @@ -5,8 +5,8 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_core::types::{BlockId, BlockTag, DeclaredClassItem, MaybePendingStateUpdate, NonceUpdate, StarknetError}; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; @@ -18,12 +18,8 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), let rpc = madara.get_starknet_client().await; assert_matches!( - rpc - .get_state_update( - BlockId::Hash(FieldElement::ZERO), - ) - .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.get_state_update(BlockId::Hash(FieldElement::ZERO)).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -55,10 +51,7 @@ async fn returns_correct_state_diff_transfer(madara: &ThreadSafeMadaraClient) -> let state_update = match rpc.get_state_update(BlockId::Tag(BlockTag::Latest)).await.unwrap() { MaybePendingStateUpdate::Update(update) => update, MaybePendingStateUpdate::PendingUpdate(_) => { - return Err(anyhow!( - "Expected update, got pending -update" - )); + return Err(anyhow!("Expected update, got pending update")); } }; let block_hash_and_number = rpc.block_hash_and_number().await?; diff --git a/starknet-rpc-test/get_storage_at.rs b/starknet-rpc-test/get_storage_at.rs index ff42624e86..99381777f1 100644 --- a/starknet-rpc-test/get_storage_at.rs +++ b/starknet-rpc-test/get_storage_at.rs @@ -4,9 +4,9 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_core::types::{BlockId, StarknetError}; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; -use starknet_rpc_test::constants::{FEE_TOKEN_ADDRESS, MAX_U256}; +use starknet_rpc_test::constants::{ETH_FEE_TOKEN_ADDRESS, MAX_U256}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; #[rstest] @@ -14,17 +14,16 @@ use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); assert_matches!( - rpc - .get_storage_at( + rpc.get_storage_at( fee_token_address, FieldElement::from_hex_be("0x7b62949c85c6af8a50c11c22927f9302f7a2e40bc93b4c988415915b0f97f09").unwrap(), BlockId::Hash(FieldElement::ZERO), ) .await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -39,19 +38,14 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( FieldElement::from_hex_be("0x051e59c2c182a58fb0a74349bfa4769cbbcba32547591dd3fb1def8623997d00") .expect("Invalid Contract Address"); - assert_matches!(rpc - .get_storage_at( + assert_matches!( + rpc.get_storage_at( invalid_contract_address, FieldElement::from_hex_be("0x7b62949c85c6af8a50c11c22927f9302f7a2e40bc93b4c988415915b0f97f09").unwrap(), BlockId::Number(0), ) .await, - Err(StarknetProviderError( - StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(code), - .. - } - )) if code == StarknetError::ContractNotFound + Err(StarknetProviderError(StarknetError::ContractNotFound)) ); Ok(()) @@ -62,7 +56,7 @@ async fn fail_non_existing_contract(madara: &ThreadSafeMadaraClient) -> Result<( async fn work_ok_at_previous_contract(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); assert_eq!( rpc.get_storage_at( @@ -82,7 +76,7 @@ async fn work_ok_at_previous_contract(madara: &ThreadSafeMadaraClient) -> Result async fn return_0_for_uninitialized_key(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).expect("Invalid Contract Address"); assert_eq!( rpc.get_storage_at(fee_token_address, FieldElement::from_hex_be("0x1").unwrap(), BlockId::Number(0),).await?, diff --git a/starknet-rpc-test/get_transaction_by_blockid_and_index.rs b/starknet-rpc-test/get_transaction_by_blockid_and_index.rs index f2099fb97c..a62e2efc92 100644 --- a/starknet-rpc-test/get_transaction_by_blockid_and_index.rs +++ b/starknet-rpc-test/get_transaction_by_blockid_and_index.rs @@ -7,8 +7,8 @@ use starknet_core::types::{ BlockId, BlockTag, InvokeTransaction, InvokeTransactionV1, MaybePendingBlockWithTxs, StarknetError, Transaction, }; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{ARGENT_CONTRACT_ADDRESS, MINT_AMOUNT, SIGNER_PRIVATE, TEST_CONTRACT_CLASS_HASH}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; @@ -21,10 +21,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.get_transaction_by_block_id_and_index(BlockId::Hash(FieldElement::ZERO), 0).await, - Err(StarknetProviderError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::BlockNotFound), - .. - })) + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -37,10 +34,7 @@ async fn fail_out_of_block_index(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.get_transaction_by_block_id_and_index(BlockId::Tag(BlockTag::Latest), u64::MAX).await, - Err(StarknetProviderError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::InvalidTransactionIndex), - .. - })) + Err(StarknetProviderError(StarknetError::InvalidTransactionIndex)) ); Ok(()) diff --git a/starknet-rpc-test/get_transaction_by_hash.rs b/starknet-rpc-test/get_transaction_by_hash.rs index a4cdf7d443..758a4a6a2a 100644 --- a/starknet-rpc-test/get_transaction_by_hash.rs +++ b/starknet-rpc-test/get_transaction_by_hash.rs @@ -4,7 +4,7 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_core::types::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, SIGNER_PRIVATE}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{assert_poll, build_single_owner_account, AccountActions}; @@ -49,10 +49,7 @@ async fn fail_invalid_transaction_hash(madara: &ThreadSafeMadaraClient) -> Resul assert_matches!( rpc.get_transaction_by_hash(FieldElement::from_hex_be("0x123").unwrap()).await, - Err(ProviderError::StarknetError(StarknetErrorWithMessage { - code: MaybeUnknownErrorCode::Known(StarknetError::TransactionHashNotFound), - message: _ - })) + Err(ProviderError::StarknetError(StarknetError::TransactionHashNotFound)) ); Ok(()) diff --git a/starknet-rpc-test/get_transaction_receipt.rs b/starknet-rpc-test/get_transaction_receipt.rs index 4c98097671..bea26eb371 100644 --- a/starknet-rpc-test/get_transaction_receipt.rs +++ b/starknet-rpc-test/get_transaction_receipt.rs @@ -5,15 +5,15 @@ use std::vec; use assert_matches::assert_matches; use rstest::rstest; use starknet_core::types::{ - Event, ExecutionResult, MaybePendingTransactionReceipt, MsgToL1, PendingTransactionReceipt, + Event, ExecutionResult, FeePayment, MaybePendingTransactionReceipt, MsgToL1, PendingTransactionReceipt, PriceUnit, TransactionFinalityStatus, TransactionReceipt, }; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; use starknet_providers::Provider; use starknet_rpc_test::constants::{ - ARGENT_CONTRACT_ADDRESS, CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, FEE_TOKEN_ADDRESS, SEQUENCER_ADDRESS, SIGNER_PRIVATE, - UDC_ADDRESS, + ARGENT_CONTRACT_ADDRESS, CAIRO_1_ACCOUNT_CONTRACT_CLASS_HASH, ETH_FEE_TOKEN_ADDRESS, SEQUENCER_ADDRESS, + SIGNER_PRIVATE, UDC_ADDRESS, }; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{ @@ -49,8 +49,8 @@ async fn work_with_invoke_transaction(madara: &ThreadSafeMadaraClient) -> Result }; let invoke_tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); - let expected_fee = FieldElement::from_hex_be("0xf032").unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); + let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0xf032").unwrap(), unit: PriceUnit::Wei }; match invoke_tx_receipt { Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke(receipt))) => { @@ -87,7 +87,7 @@ async fn work_with_invoke_transaction(madara: &ThreadSafeMadaraClient) -> Result data: vec![ FieldElement::from_hex_be(ARGENT_CONTRACT_ADDRESS).unwrap(), // from FieldElement::from_hex_be(SEQUENCER_ADDRESS).unwrap(), // to (sequencer address) - expected_fee, // value low + expected_fee.amount, // value low FieldElement::ZERO, // value high ], }, @@ -132,7 +132,7 @@ async fn work_with_pending_invoke_transaction(madara: &ThreadSafeMadaraClient) - match invoke_tx_pending_receipt { MaybePendingTransactionReceipt::PendingReceipt(PendingTransactionReceipt::Invoke(receipt)) => { assert_eq!(receipt.transaction_hash, rpc_response.transaction_hash); - assert!(receipt.actual_fee > FieldElement::ZERO); + assert!(receipt.actual_fee.amount > FieldElement::ZERO); assert_eq_msg_to_l1(receipt.messages_sent, vec![]); assert_eq!(receipt.events, vec![]); assert_matches!(receipt.execution_result, ExecutionResult::Succeeded); @@ -164,16 +164,19 @@ async fn work_with_declare_transaction(madara: &ThreadSafeMadaraClient) -> Resul _ => panic!("expected execution result"), }; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); - let expected_fee = - FieldElement::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000003066").unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); + let expected_fee = FeePayment { + amount: FieldElement::from_hex_be("0x0000000000000000000000000000000000000000000000000000000000003066") + .unwrap(), + unit: PriceUnit::Wei, + }; let expected_events = vec![Event { from_address: fee_token_address, keys: vec![get_selector_from_name("Transfer").unwrap()], data: vec![ FieldElement::from_hex_be(ARGENT_CONTRACT_ADDRESS).unwrap(), // from FieldElement::from_hex_be(SEQUENCER_ADDRESS).unwrap(), // to (sequencer address) - expected_fee, // value low + expected_fee.amount, // value low FieldElement::ZERO, // value high ], }]; @@ -221,7 +224,7 @@ async fn work_with_pending_declare_transaction(madara: &ThreadSafeMadaraClient) match pending_receipt { MaybePendingTransactionReceipt::PendingReceipt(PendingTransactionReceipt::Declare(tx_receipt)) => { - assert!(tx_receipt.actual_fee > FieldElement::ZERO); + assert!(tx_receipt.actual_fee.amount > FieldElement::ZERO); assert_eq_msg_to_l1(tx_receipt.messages_sent, vec![]); assert_eq!(tx_receipt.events, vec![]); assert_matches!(tx_receipt.execution_result, ExecutionResult::Succeeded); @@ -271,8 +274,8 @@ async fn work_with_deploy_account_transaction(madara: &ThreadSafeMadaraClient) - }; let account_deployment_tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); - let expected_fee = FieldElement::from_hex_be("0x7850").unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); + let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0x7850").unwrap(), unit: PriceUnit::Wei }; match account_deployment_tx_receipt { Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::DeployAccount(receipt))) => { @@ -288,7 +291,7 @@ async fn work_with_deploy_account_transaction(madara: &ThreadSafeMadaraClient) - data: vec![ account_address, FieldElement::from_hex_be(SEQUENCER_ADDRESS).unwrap(), // to - expected_fee, // value low + expected_fee.amount, // value low FieldElement::ZERO, // value high ], }], @@ -347,7 +350,7 @@ async fn work_with_pending_deploy_account_transaction(madara: &ThreadSafeMadaraC match account_deployment_tx_receipt { MaybePendingTransactionReceipt::PendingReceipt(PendingTransactionReceipt::DeployAccount(receipt)) => { assert_eq!(receipt.transaction_hash, rpc_response.transaction_hash); - assert!(receipt.actual_fee > FieldElement::ZERO); + assert!(receipt.actual_fee.amount > FieldElement::ZERO); assert_eq_msg_to_l1(receipt.messages_sent, vec![]); assert_eq!(receipt.events, vec![]); assert_matches!(receipt.execution_result, ExecutionResult::Succeeded); @@ -381,8 +384,8 @@ async fn ensure_transfer_fee_event_not_messed_up_with_similar_transfer( _ => panic!("expected execution result"), }; let tx_receipt = get_transaction_receipt(&rpc, rpc_response.transaction_hash).await; - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); - let expected_fee = FieldElement::from_hex_be("0xf032").unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); + let expected_fee = FeePayment { amount: FieldElement::from_hex_be("0xf032").unwrap(), unit: PriceUnit::Wei }; match tx_receipt { Ok(MaybePendingTransactionReceipt::Receipt(TransactionReceipt::Invoke(mut receipt))) => { @@ -410,7 +413,7 @@ async fn ensure_transfer_fee_event_not_messed_up_with_similar_transfer( data: vec![ FieldElement::from_hex_be(ARGENT_CONTRACT_ADDRESS).unwrap(), // from FieldElement::from_hex_be(SEQUENCER_ADDRESS).unwrap(), // to - expected_fee, // value low + expected_fee.amount, // value low FieldElement::ZERO, // value high ], }, diff --git a/starknet-rpc-test/simulate_transaction.rs b/starknet-rpc-test/simulate_transaction.rs index d9669b290d..361917a379 100644 --- a/starknet-rpc-test/simulate_transaction.rs +++ b/starknet-rpc-test/simulate_transaction.rs @@ -4,12 +4,13 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_accounts::{Call, ConnectedAccount}; use starknet_core::types::{ - BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedTransaction, SimulationFlag, StarknetError, + BlockId, BlockTag, BroadcastedInvokeTransaction, BroadcastedInvokeTransactionV1, BroadcastedTransaction, + SimulationFlag, StarknetError, }; use starknet_core::utils::get_selector_from_name; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{ACCOUNT_CONTRACT, ARGENT_CONTRACT_ADDRESS, SIGNER_PRIVATE, TEST_CONTRACT_ADDRESS}; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; @@ -19,23 +20,24 @@ use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let ok_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::ZERO, - signature: vec![], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), - calldata: vec![ - FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), - get_selector_from_name("sqrt").unwrap(), - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from(81u8), - ], - is_query: false, - }); + let ok_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::ZERO, + signature: vec![], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), + calldata: vec![ + FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), + get_selector_from_name("sqrt").unwrap(), + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from(81u8), + ], + is_query: false, + })); assert_matches!( - rpc.simulate_transactions(BlockId::Hash(FieldElement::ZERO),&[ok_invoke_transaction], []).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + rpc.simulate_transactions(BlockId::Hash(FieldElement::ZERO), &[ok_invoke_transaction], []).await, + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -46,23 +48,24 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), async fn fail_max_fee_too_big(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let ok_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::from_hex_be("0x100000000000000000000000000000000").unwrap(), // u128::MAX + 1 - signature: vec![], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), - calldata: vec![ - FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), - get_selector_from_name("sqrt").unwrap(), - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from(81u8), - ], - is_query: false, - }); + let ok_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::from_hex_be("0x100000000000000000000000000000000").unwrap(), // u128::MAX + 1 + signature: vec![], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), + calldata: vec![ + FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), + get_selector_from_name("sqrt").unwrap(), + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from(81u8), + ], + is_query: false, + })); assert_matches!( rpc.simulate_transactions(BlockId::Tag(BlockTag::Latest), &[ok_invoke_transaction], []).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Unknown(500), message })) if message == "Internal server error" + Err(StarknetProviderError(StarknetError::UnexpectedError(message))) if message == "Internal server error" ); Ok(()) @@ -73,35 +76,39 @@ async fn fail_max_fee_too_big(madara: &ThreadSafeMadaraClient) -> Result<(), any async fn fail_if_one_txn_cannot_be_executed(madara: &ThreadSafeMadaraClient) -> Result<(), anyhow::Error> { let rpc = madara.get_starknet_client().await; - let bad_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::default(), - nonce: FieldElement::ZERO, - sender_address: FieldElement::default(), - signature: vec![], - calldata: vec![FieldElement::from_hex_be("0x0").unwrap()], - is_query: false, - }); - - let ok_invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { - max_fee: FieldElement::ZERO, - signature: vec![], - nonce: FieldElement::ZERO, - sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), - calldata: vec![ - FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), - get_selector_from_name("sqrt").unwrap(), - FieldElement::from_hex_be("1").unwrap(), - FieldElement::from(81u8), - ], - is_query: false, - }); + let bad_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::default(), + nonce: FieldElement::ZERO, + sender_address: FieldElement::default(), + signature: vec![], + calldata: vec![FieldElement::from_hex_be("0x0").unwrap()], + is_query: false, + })); + + let ok_invoke_transaction = + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + max_fee: FieldElement::ZERO, + signature: vec![], + nonce: FieldElement::ZERO, + sender_address: FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(), + calldata: vec![ + FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), + get_selector_from_name("sqrt").unwrap(), + FieldElement::from_hex_be("1").unwrap(), + FieldElement::from(81u8), + ], + is_query: false, + })); assert_matches!( - rpc.simulate_transactions(BlockId::Tag(BlockTag::Latest),&[ - bad_invoke_transaction, - ok_invoke_transaction, - ],[] ).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::ContractError + rpc.simulate_transactions( + BlockId::Tag(BlockTag::Latest), + &[bad_invoke_transaction, ok_invoke_transaction,], + [] + ) + .await, + Err(StarknetProviderError(StarknetError::ContractError(_))) ); Ok(()) @@ -117,7 +124,7 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) -> Result<(), let mut madara_write_lock = madara.write().await; let _ = madara_write_lock.create_empty_block().await; - let tx = BroadcastedInvokeTransaction { + let tx = BroadcastedInvokeTransactionV1 { sender_address, calldata: vec![ FieldElement::from_hex_be(TEST_CONTRACT_ADDRESS).unwrap(), @@ -131,19 +138,22 @@ async fn works_ok_on_no_validate(madara: &ThreadSafeMadaraClient) -> Result<(), is_query: false, }; - let invoke_transaction = BroadcastedTransaction::Invoke(tx.clone()); + let invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(tx.clone())); let invoke_transaction_2 = - BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { nonce: FieldElement::ONE, ..tx }); + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + nonce: FieldElement::ONE, + ..tx + })); let simulations = rpc .simulate_transactions(BlockId::Tag(BlockTag::Latest), &[invoke_transaction, invoke_transaction_2], []) .await?; assert_eq!(simulations.len(), 2); - assert_eq!(simulations[0].fee_estimation.gas_consumed, 0); - assert_eq!(simulations[0].fee_estimation.overall_fee, 210); - assert_eq!(simulations[0].fee_estimation.gas_price, 0); + assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO); + assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(210u128)); + assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO); Ok(()) } @@ -168,9 +178,9 @@ async fn works_ok_on_validate_with_signature(madara: &ThreadSafeMadaraClient) -> let simulations = rpc.simulate_transactions(BlockId::Tag(BlockTag::Latest), &[invoke_transaction], []).await?; assert_eq!(simulations.len(), 1); - assert_eq!(simulations[0].fee_estimation.gas_consumed, 0); - assert_eq!(simulations[0].fee_estimation.overall_fee, 240); - assert_eq!(simulations[0].fee_estimation.gas_price, 0); + assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO); + assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(240u128)); + assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO); Ok(()) } @@ -199,9 +209,9 @@ async fn works_ok_on_validate_without_signature_with_skip_validate( .await?; assert_eq!(simulations.len(), 1); - assert_eq!(simulations[0].fee_estimation.gas_consumed, 0); - assert_eq!(simulations[0].fee_estimation.overall_fee, 220); - assert_eq!(simulations[0].fee_estimation.gas_price, 0); + assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO); + assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(220u128)); + assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO); Ok(()) } @@ -213,7 +223,7 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara let sender_address = FieldElement::from_hex_be(ACCOUNT_CONTRACT).unwrap(); - let tx = BroadcastedInvokeTransaction { + let tx = BroadcastedInvokeTransactionV1 { max_fee: FieldElement::from(0u8), signature: vec![], nonce: FieldElement::ZERO, @@ -227,10 +237,13 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara is_query: false, }; - let invoke_transaction = BroadcastedTransaction::Invoke(tx.clone()); + let invoke_transaction = BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(tx.clone())); let invoke_transaction_2 = - BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction { nonce: FieldElement::ONE, ..tx }); + BroadcastedTransaction::Invoke(BroadcastedInvokeTransaction::V1(BroadcastedInvokeTransactionV1 { + nonce: FieldElement::ONE, + ..tx + })); let simulations = rpc .simulate_transactions( @@ -241,9 +254,9 @@ async fn works_ok_without_max_fee_with_skip_fee_charge(madara: &ThreadSafeMadara .await?; assert_eq!(simulations.len(), 2); - assert_eq!(simulations[0].fee_estimation.gas_consumed, 0); - assert_eq!(simulations[0].fee_estimation.overall_fee, 210); - assert_eq!(simulations[0].fee_estimation.gas_price, 0); + assert_eq!(simulations[0].fee_estimation.gas_consumed, FieldElement::ZERO); + assert_eq!(simulations[0].fee_estimation.overall_fee, FieldElement::from(210u128)); + assert_eq!(simulations[0].fee_estimation.gas_price, FieldElement::ZERO); Ok(()) } diff --git a/starknet-rpc-test/src/constants.rs b/starknet-rpc-test/src/constants.rs index 99a55fbe7d..9bf333b2ff 100644 --- a/starknet-rpc-test/src/constants.rs +++ b/starknet-rpc-test/src/constants.rs @@ -23,7 +23,7 @@ pub const TEST_CONTRACT_CLASS_HASH: &str = "0x04c5efa8dc6f0554da51f125d04e379ac4 pub const MINT_AMOUNT: &str = "0x0000000000000000000000000000000000000000000000000000000000000001"; pub const DEPLOY_ACCOUNT_COST: &str = "0x00000000000000000000000000000000000000000000000000000000ffffffff"; pub const CONTRACT_ADDRESS: &str = "0x0000000000000000000000000000000000000000000000000000000000000001"; -pub const FEE_TOKEN_ADDRESS: &str = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"; +pub const ETH_FEE_TOKEN_ADDRESS: &str = "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"; pub const TOKEN_CLASS_HASH: &str = "0x0000000000000000000000000000000000000000000000000000000000010000"; pub const ARGENT_CONTRACT_ADDRESS: &str = "0x0000000000000000000000000000000000000000000000000000000000000002"; pub const OZ_CONTRACT_ADDRESS: &str = "0x0000000000000000000000000000000000000000000000000000000000000003"; diff --git a/starknet-rpc-test/src/utils.rs b/starknet-rpc-test/src/utils.rs index a3b14e96b4..413fbcc6df 100644 --- a/starknet-rpc-test/src/utils.rs +++ b/starknet-rpc-test/src/utils.rs @@ -18,7 +18,7 @@ use starknet_providers::jsonrpc::{HttpTransport, JsonRpcClient}; use starknet_providers::{Provider, ProviderError}; use starknet_signers::{LocalWallet, SigningKey}; -use crate::constants::{FEE_TOKEN_ADDRESS, MAX_FEE_OVERRIDE}; +use crate::constants::{ETH_FEE_TOKEN_ADDRESS, MAX_FEE_OVERRIDE}; use crate::{ RpcAccount, RpcOzAccountFactory, SendTransactionError, TransactionAccountDeployment, TransactionDeclaration, TransactionExecution, TransactionLegacyDeclaration, TransactionResult, @@ -133,7 +133,7 @@ impl AccountActions for SingleOwnerAccount<&JsonRpcClient, LocalW transfer_amount: U256, nonce: Option, ) -> TransactionExecution { - let fee_token_address = FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(); + let fee_token_address = FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(); self.invoke_contract( fee_token_address, "transfer", diff --git a/starknet-rpc-test/trace_block.rs b/starknet-rpc-test/trace_block.rs index 88c66af61e..c7d70dbe05 100644 --- a/starknet-rpc-test/trace_block.rs +++ b/starknet-rpc-test/trace_block.rs @@ -7,10 +7,10 @@ use starknet_core::types::{ TransactionTrace, TransactionTraceWithHash, }; use starknet_ff::FieldElement; +use starknet_providers::Provider; use starknet_providers::ProviderError::StarknetError as StarknetProviderError; -use starknet_providers::{MaybeUnknownErrorCode, Provider, StarknetErrorWithMessage}; use starknet_rpc_test::constants::{ - ARGENT_ACCOUNT_CLASS_HASH_CAIRO_0, ARGENT_CONTRACT_ADDRESS, FEE_TOKEN_ADDRESS, SIGNER_PRIVATE, + ARGENT_ACCOUNT_CLASS_HASH_CAIRO_0, ARGENT_CONTRACT_ADDRESS, ETH_FEE_TOKEN_ADDRESS, SIGNER_PRIVATE, }; use starknet_rpc_test::fixtures::{madara, ThreadSafeMadaraClient}; use starknet_rpc_test::utils::{build_single_owner_account, AccountActions}; @@ -23,7 +23,7 @@ async fn fail_non_existing_block(madara: &ThreadSafeMadaraClient) -> Result<(), assert_matches!( rpc.trace_block_transactions(BlockId::Hash(FieldElement::ZERO)).await, - Err(StarknetProviderError(StarknetErrorWithMessage { code: MaybeUnknownErrorCode::Known(code), .. })) if code == StarknetError::BlockNotFound + Err(StarknetProviderError(StarknetError::BlockNotFound)) ); Ok(()) @@ -72,15 +72,15 @@ async fn work_for_one_invoke_tx(madara: &ThreadSafeMadaraClient) -> Result<(), a FieldElement::from_hex_be("0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e").unwrap(); // This is legacy starknet `__execute__` calls encoding let expected_calldata = vec![ - FieldElement::ONE, // number of calls - FieldElement::from_hex_be(FEE_TOKEN_ADDRESS).unwrap(), // contract to call - transfer_selector, // selector - FieldElement::ZERO, // data offset - FieldElement::from(3u8), // data len - FieldElement::from(3u8), // Calldata len - recipient_account, // Recipient address - FieldElement::ONE, // Amount low - FieldElement::ZERO, // Amount high + FieldElement::ONE, // number of calls + FieldElement::from_hex_be(ETH_FEE_TOKEN_ADDRESS).unwrap(), // contract to call + transfer_selector, // selector + FieldElement::ZERO, // data offset + FieldElement::from(3u8), // data len + FieldElement::from(3u8), // Calldata len + recipient_account, // Recipient address + FieldElement::ONE, // Amount low + FieldElement::ZERO, // Amount high ]; assert_eq!(traces.len(), 1);