diff --git a/.env.example b/.env.example index 55169771..835a1e7f 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,8 @@ PROVIDER_URL_ETHEREUM_SEPOLIA=https://goerli.infura.io/v3/your-infura-api-key # this value is optional PROVIDER_CHUNK_SIZE_ETHEREUM_SEPOLIA=2000 +RPC_URL_STARKNET_SEPOLIA=# if it's starknet make sure to use pathfinder + # Optional DRY_RUN_CAIRO_PATH= # path for dry run cairo SOUND_RUN_CAIRO_PATH= # path for sound run cairo diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fb77c66..55d64550 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,6 @@ jobs: run: | rustup component add clippy rustup component add rustfmt - - name: Install cargo-make - run: cargo install --debug cargo-make + - uses: taiki-e/install-action@just - name: Run clippy and formatter checks - run: cargo make run-ci-flow + run: just run-ci-flow diff --git a/Cargo.lock b/Cargo.lock index 8b0a2d9f..c7f0646c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] @@ -82,11 +82,10 @@ dependencies = [ [[package]] name = "alloy-chains" -version = "0.1.38" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "156bfc5dcd52ef9a5f33381701fa03310317e14c65093a9430d3e3557b08dcd3" +checksum = "b68b94c159bcc2ca5f758b8663d7b00fc7c5e40569984595ddf2221b0f7f7f6e" dependencies = [ - "alloy-primitives", "num_enum", "strum", ] @@ -295,7 +294,7 @@ dependencies = [ "foldhash", "hashbrown 0.15.0", "hex-literal", - "indexmap 2.6.0", + "indexmap 2.5.0", "itoa", "k256", "keccak-asm", @@ -337,7 +336,7 @@ dependencies = [ "futures-utils-wasm", "lru", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.7", "serde", "serde_json", "thiserror", @@ -361,7 +360,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", ] @@ -384,7 +383,7 @@ checksum = "4d0f2d905ebd295e7effec65e5f6868d153936130ae718352771de3e7d03c75c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -402,12 +401,12 @@ dependencies = [ "alloy-transport-ws", "futures", "pin-project", - "reqwest 0.12.8", + "reqwest 0.12.7", "serde", "serde_json", "tokio", "tokio-stream", - "tower", + "tower 0.5.1", "tracing", "url", ] @@ -510,7 +509,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -523,11 +522,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck 0.5.0", - "indexmap 2.6.0", + "indexmap 2.5.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", "syn-solidity", "tiny-keccak", ] @@ -545,7 +544,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.79", + "syn 2.0.77", "syn-solidity", ] @@ -586,7 +585,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", - "tower", + "tower 0.5.1", "tracing", "url", ] @@ -599,9 +598,9 @@ checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" dependencies = [ "alloy-json-rpc", "alloy-transport", - "reqwest 0.12.8", + "reqwest 0.12.7", "serde_json", - "tower", + "tower 0.5.1", "tracing", "url", ] @@ -635,7 +634,7 @@ dependencies = [ "alloy-transport", "futures", "http 1.1.0", - "rustls 0.23.14", + "rustls 0.23.13", "serde_json", "tokio", "tokio-tungstenite", @@ -866,9 +865,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-stream" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", @@ -877,24 +876,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -927,14 +926,14 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -1067,9 +1066,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.2" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" dependencies = [ "serde", ] @@ -1091,9 +1090,9 @@ dependencies = [ [[package]] name = "cairo-lang-casm" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4d6659539ace9649c8e8a7434e51b0c50a7a700111d0a2b967dde220ddff49" +checksum = "60a4b4ca8473c25d1e760c83c2a49d953197556f82f6feb636004d3b6d6cc4a7" dependencies = [ "cairo-lang-utils", "indoc", @@ -1105,9 +1104,9 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a416c5871960fb4823160ebef2abc51e0c1b86fef1e97a1ebb2e5f3c3795d3" +checksum = "a0cd844e568f51e39729e8ac18bd27ada2e2b6dc9138f8c81adad48456480681" dependencies = [ "cairo-lang-utils", "good_lp", @@ -1115,9 +1114,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f55450494e959c1ae26c52a71075767a90f76e3ecca6e81056dd7517e8ba0" +checksum = "891488c1a3184ce91679f5bdb63015a1d24769a48bd07e5d51a1779d0031dfbe" dependencies = [ "anyhow", "cairo-lang-utils", @@ -1142,9 +1141,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053dd520e0b9d1c1078d93ea69045f6f334c3d41b4b75db183ab33e32cfd8570" +checksum = "ea7752cd48c86b2cde8603b753a6df4da086dacd16a73d288854d5f040b51171" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1158,9 +1157,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a73227867377efc62ebb893cddaa88df3940bf2be5dbdc2f0b00f9edf69288e" +checksum = "340892a09c9421414b2ac45b03c705f16e2bd737e4559dfd98ee1d20718dec9e" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1174,9 +1173,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7162fb3c93960dfc6d8005b65064e518e3f1ed6102e8981b42ea41879c331184" +checksum = "1c22ff7e8113a46a907f82f191096c96935cc48247e3079971ddf536ccc2f4f8" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -1195,9 +1194,9 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a51b80c117e2b05a6d300f2e2247892cc99e42e950e79f6085e6ed6cbcb44d12" +checksum = "5bf41941776e7410a8853a8e2a116292fc24d219df1989a92ffe5ab0e98037eb" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -1205,9 +1204,9 @@ dependencies = [ [[package]] name = "cairo-lang-starknet-classes" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "832fd9072ddf4204ca6d227c0238929349f10146bd066a98025d51ac15d27fad" +checksum = "482b8f9d7f8cc7140f1260ee71f3308a66d15bd228a06281067ca3f8f4410db2" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -1228,12 +1227,12 @@ dependencies = [ [[package]] name = "cairo-lang-utils" -version = "2.8.4" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bfc6372538143afad658c853a35bdc9f5210c5cb54e0c8f04ab78e268139466" +checksum = "73104609a7d865e4cd1de9cbf4e750683d076b6d0233bf81be511df274a26916" dependencies = [ "hashbrown 0.14.5", - "indexmap 2.6.0", + "indexmap 2.5.0", "itertools 0.12.1", "num-bigint", "num-traits 0.2.19", @@ -1249,9 +1248,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.30" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" dependencies = [ "shlex", ] @@ -1326,9 +1325,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -1336,9 +1335,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -1348,14 +1347,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -1387,9 +1386,9 @@ checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" [[package]] name = "const-hex" -version = "1.13.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" dependencies = [ "cfg-if", "cpufeatures", @@ -1592,7 +1591,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -1603,7 +1602,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -1674,7 +1673,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", "unicode-xid", ] @@ -1944,9 +1943,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide", @@ -1996,9 +1995,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -2011,9 +2010,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -2021,15 +2020,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -2038,38 +2037,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -2133,9 +2132,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "glob" @@ -2176,7 +2175,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -2216,15 +2215,13 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ - "allocator-api2", - "equivalent", "foldhash", "serde", ] [[package]] name = "hdp" -version = "0.7.0" +version = "0.8.0" dependencies = [ "alloy", "alloy-merkle-tree", @@ -2241,9 +2238,11 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "serde_with 2.3.3", + "serde_with", + "sn-trie-proofs", "starknet", "starknet-crypto", + "starknet-types-core", "tempfile", "thiserror", "tokio", @@ -2252,11 +2251,11 @@ dependencies = [ [[package]] name = "hdp-cli" -version = "0.7.0" +version = "0.8.0" dependencies = [ "alloy", "anyhow", - "clap 4.5.20", + "clap 4.5.17", "dotenv", "hdp", "inquire", @@ -2377,9 +2376,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -2389,9 +2388,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.31" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -2413,9 +2412,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -2438,7 +2437,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.31", + "hyper 0.14.30", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", @@ -2451,7 +2450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.31", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", @@ -2465,7 +2464,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-util", "native-tls", "tokio", @@ -2475,28 +2474,29 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.9" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.5.0", + "hyper 1.4.1", "pin-project-lite", "socket2", "tokio", + "tower 0.4.13", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2582,12 +2582,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.14.5", "serde", ] @@ -2640,9 +2640,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is_terminal_polyfill" @@ -2694,18 +2694,18 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] [[package]] name = "k256" -version = "0.13.4" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" dependencies = [ "cfg-if", "ecdsa", @@ -2757,7 +2757,7 @@ dependencies = [ "petgraph", "pico-args", "regex", - "regex-syntax 0.8.5", + "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", @@ -2771,7 +2771,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata 0.4.8", + "regex-automata 0.4.7", ] [[package]] @@ -2804,9 +2804,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -2848,11 +2848,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.5" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ - "hashbrown 0.15.0", + "hashbrown 0.14.5", ] [[package]] @@ -3065,23 +3065,23 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] name = "object" -version = "0.36.5" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "oorandom" @@ -3091,9 +3091,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl" -version = "0.10.67" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8cefcf97f41316955f9294cd61f639bdcfa9f2f230faac6cb896aa8ab64704" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -3112,7 +3112,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -3123,9 +3123,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -3217,9 +3217,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", "thiserror", @@ -3233,7 +3233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.5.0", ] [[package]] @@ -3263,22 +3263,22 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project" -version = "1.1.6" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.6" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -3305,9 +3305,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" @@ -3373,7 +3373,7 @@ dependencies = [ [[package]] name = "private-input-module" -version = "0.7.0" +version = "0.8.0" dependencies = [ "hdp", "serde_json", @@ -3408,14 +3408,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -3434,7 +3434,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.5", + "regex-syntax 0.8.4", "rusty-fork", "tempfile", "unarray", @@ -3535,9 +3535,9 @@ checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -3555,14 +3555,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", - "regex-syntax 0.8.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -3576,13 +3576,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.4", ] [[package]] @@ -3593,9 +3593,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" @@ -3611,7 +3611,7 @@ dependencies = [ "h2", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.31", + "hyper 0.14.30", "hyper-rustls", "hyper-tls 0.5.0", "ipnet", @@ -3643,9 +3643,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", "bytes", @@ -3654,7 +3654,7 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.5.0", + "hyper 1.4.1", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -3665,7 +3665,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile 2.2.0", + "rustls-pemfile 2.1.3", "serde", "serde_json", "serde_urlencoded", @@ -3751,7 +3751,7 @@ version = "0.17.0-pre.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719825638c59fd26a55412a24561c7c5bcf54364c88b9a7a04ba08a6eafaba8d" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.5.0", "lock_api", "oorandom", "parking_lot", @@ -3771,7 +3771,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -3843,9 +3843,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring", @@ -3866,18 +3866,19 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.2.0" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -3902,9 +3903,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -3944,9 +3945,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ "windows-sys 0.59.0", ] @@ -3973,7 +3974,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4033,9 +4034,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -4088,7 +4089,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4099,7 +4100,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4149,23 +4150,7 @@ dependencies = [ "indexmap 1.9.3", "serde", "serde_json", - "serde_with_macros 2.3.3", - "time", -] - -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros 3.11.0", + "serde_with_macros", "time", ] @@ -4178,19 +4163,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.79", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4320,6 +4293,33 @@ dependencies = [ "serde", ] +[[package]] +name = "sn-merkle-trie" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a46c1daa6d9bef421896da0fd2d17c80c02c93a966ca832c8f607b106d443ae0" +dependencies = [ + "anyhow", + "bitvec", + "starknet-types-core", +] + +[[package]] +name = "sn-trie-proofs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b10f58b720d5e2244dbb5eeed1546e3898c6c4d7b1909de863a447586c746" +dependencies = [ + "bitflags 2.6.0", + "reqwest 0.11.27", + "serde_json", + "sn-merkle-trie", + "starknet-types-core", + "starknet-types-rpc", + "thiserror", + "tokio", +] + [[package]] name = "socket2" version = "0.5.7" @@ -4371,7 +4371,7 @@ checksum = "1e633a772f59214c296d5037c95c36b72792c9360323818da2b625c7b4ec4b49" dependencies = [ "starknet-accounts", "starknet-contract", - "starknet-core 0.11.1", + "starknet-core", "starknet-crypto", "starknet-macros", "starknet-providers", @@ -4386,7 +4386,7 @@ checksum = "eee8a6b588a22c7e79f5d8d4e33413387db63a8beb98be8610138541794cc0a5" dependencies = [ "async-trait", "auto_impl", - "starknet-core 0.11.1", + "starknet-core", "starknet-crypto", "starknet-providers", "starknet-signers", @@ -4401,9 +4401,9 @@ checksum = "a5f91344f1e0b81873b6dc235c50ae4d084c6ea4dd4a1e3e27ad895803adb610" dependencies = [ "serde", "serde_json", - "serde_with 2.3.3", + "serde_with", "starknet-accounts", - "starknet-core 0.11.1", + "starknet-core", "starknet-providers", "thiserror", ] @@ -4421,26 +4421,7 @@ dependencies = [ "serde", "serde_json", "serde_json_pythonic", - "serde_with 2.3.3", - "sha3", - "starknet-crypto", - "starknet-types-core", -] - -[[package]] -name = "starknet-core" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538240cbe6663c673fe77465f294da707080f39678dd7066761554899e46100" -dependencies = [ - "base64 0.21.7", - "crypto-bigint", - "flate2", - "hex", - "serde", - "serde_json", - "serde_json_pythonic", - "serde_with 3.11.0", + "serde_with", "sha3", "starknet-crypto", "starknet-types-core", @@ -4448,9 +4429,9 @@ dependencies = [ [[package]] name = "starknet-crypto" -version = "0.7.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a5064173a8e8d2675e67744fd07f310de44573924b6b7af225a6bdd8102913" +checksum = "ff2a821ad8d98c6c3e4d0e5097f3fe6e2ed120ada9d32be87cd1330c7923a2f0" dependencies = [ "crypto-bigint", "hex", @@ -4460,28 +4441,40 @@ dependencies = [ "num-traits 0.2.19", "rfc6979", "sha2", + "starknet-crypto-codegen", "starknet-curve", "starknet-types-core", "zeroize", ] +[[package]] +name = "starknet-crypto-codegen" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e179dedc3fa6da064e56811d3e05d446aa2f7459e4eb0e3e49378a337235437" +dependencies = [ + "starknet-curve", + "starknet-types-core", + "syn 2.0.77", +] + [[package]] name = "starknet-curve" -version = "0.5.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcde6bd74269b8161948190ace6cf069ef20ac6e79cd2ba09b320efa7500b6de" +checksum = "56935b306dcf0b8f14bb2a1257164b8478bb8be4801dfae0923f5b266d1b457c" dependencies = [ "starknet-types-core", ] [[package]] name = "starknet-macros" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8986a940af916fc0a034f4e42c6ba76d94f1e97216d75447693dfd7aefaf3ef2" +checksum = "f4fe4f8d615329410578cbedcdbaa4a36c7f28f68c3f3ac56006cfbdaeaa2b41" dependencies = [ - "starknet-core 0.12.0", - "syn 2.0.79", + "starknet-core", + "syn 2.0.77", ] [[package]] @@ -4499,8 +4492,8 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "serde_with 2.3.3", - "starknet-core 0.11.1", + "serde_with", + "starknet-core", "thiserror", "url", ] @@ -4517,7 +4510,7 @@ dependencies = [ "eth-keystore", "getrandom", "rand", - "starknet-core 0.11.1", + "starknet-core", "starknet-crypto", "thiserror", ] @@ -4537,6 +4530,16 @@ dependencies = [ "serde", ] +[[package]] +name = "starknet-types-rpc" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d717a1b5ff67fa9ec13b09381513a4824fdd73ec5440fcc116088be6744aac4" +dependencies = [ + "serde", + "starknet-types-core", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -4581,7 +4584,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4603,9 +4606,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -4621,7 +4624,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4668,9 +4671,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", @@ -4698,22 +4701,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4826,7 +4829,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -4855,7 +4858,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.14", + "rustls 0.23.13", "rustls-pki-types", "tokio", ] @@ -4880,12 +4883,12 @@ checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" dependencies = [ "futures-util", "log", - "rustls 0.23.14", + "rustls 0.23.13", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", "tungstenite", - "webpki-roots 0.26.6", + "webpki-roots 0.26.5", ] [[package]] @@ -4909,15 +4912,30 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.5.0", "toml_datetime", "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower" version = "0.5.1" @@ -4963,7 +4981,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -5007,9 +5025,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" dependencies = [ "serde", "stable_deref_trait", @@ -5034,7 +5052,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls 0.23.14", + "rustls 0.23.13", "rustls-pki-types", "sha1", "thiserror", @@ -5049,9 +5067,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "uint" @@ -5073,9 +5091,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -5085,9 +5103,9 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] @@ -5100,15 +5118,15 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "untrusted" @@ -5203,9 +5221,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", "once_cell", @@ -5214,24 +5232,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -5241,9 +5259,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5251,28 +5269,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -5286,9 +5304,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] @@ -5519,9 +5537,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -5582,7 +5600,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] [[package]] @@ -5602,5 +5620,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.77", ] diff --git a/Cargo.toml b/Cargo.toml index ae6fba17..45df2976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,10 @@ resolver = "2" members = ["cli", "examples/private-input-module", "hdp"] [workspace.package] -version = "0.7.0" edition = "2021" +version = "0.8.0" license-file = "LICENSE" -authors = ["Pia "] +authors = ["Herodotus Data Processor Team"] repository = "https://github.com/HerodotusDev/hdp" homepage = "https://herodotus.dev/" exclude = ["benches/", "fixtures/", "examples/"] @@ -42,5 +42,6 @@ cairo-vm = "1.0.0-rc6" futures = "0.3.30" lazy_static = "1.4.0" thiserror = "1.0" +sn-trie-proofs = { version = "0.1.1" } eth-trie-proofs = "0.1.2" itertools = "0.10" diff --git a/Makefile.toml b/Makefile.toml deleted file mode 100644 index 408c717c..00000000 --- a/Makefile.toml +++ /dev/null @@ -1,29 +0,0 @@ -[env] -CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true - -[tasks.format] -install_crate = "rustfmt" -command = "cargo" -args = ["fmt", "--", "--check"] -description = "Run rustfmt to check the code formatting without making changes." - -[tasks.clean] -command = "cargo" -args = ["clean"] -description = "Clean up the project by removing the target directory." - -[tasks.clippy] -command = "cargo" -args = ["clippy", "--all-targets", "--all-features", "--", "-Dwarnings"] -description = "Run clippy to catch common mistakes and improve your Rust code." - -[tasks.test] -workspace = false -command = "cargo" -args = ["llvm-cov", "nextest", "--features", "test_utils"] -description = "Execute all unit tests in the workspace." - -[tasks.run-ci-flow] -workspace = false -description = "Run the entire CI pipeline including format, clippy, and test checks." -dependencies = ["format", "clippy", "test"] diff --git a/README.md b/README.md index 489016f7..f2128c5f 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ _Note: Fields marked with "-" are not applicable for the specified aggregate fun ```sh # CI check -cargo make run-ci-flow +just run-ci-flow ``` ### Local Run diff --git a/cli/src/commands/run_datalake.rs b/cli/src/commands/run_datalake.rs index 8feedeca..50e68505 100644 --- a/cli/src/commands/run_datalake.rs +++ b/cli/src/commands/run_datalake.rs @@ -17,7 +17,7 @@ pub struct RunDatalakeArgs { pub aggregate_fn_id: AggregationFunction, /// Optional context for applying conditions on the aggregate function "count". /// Format: "{operator}.{value}" (e.g., "eq.100" for equality, "gt.100" for greater-than). - /// Supported operators are in the [`Operator`] enum. + /// Supported operators are in the Operator enum. pub aggregate_fn_ctx: Option, #[command(subcommand)] diff --git a/cli/src/interactive.rs b/cli/src/interactive.rs index 2be26667..aed27e98 100644 --- a/cli/src/interactive.rs +++ b/cli/src/interactive.rs @@ -230,7 +230,7 @@ pub async fn run_interactive() -> anyhow::Result<()> { start_index, end_index, increment, - IncludedTypes::from(&included_types), + IncludedTypes::from_bytes(&included_types), ); DatalakeEnvelope::TransactionsInBlock(transactions_datalake) } diff --git a/hdp/Cargo.toml b/hdp/Cargo.toml index 7d91a588..e319e06b 100644 --- a/hdp/Cargo.toml +++ b/hdp/Cargo.toml @@ -24,6 +24,7 @@ serde = { workspace = true } serde_with = { workspace = true } serde_json = { workspace = true } starknet-crypto = { workspace = true } +starknet-types-core = { workspace = true } starknet = { workspace = true } thiserror.workspace = true alloy-merkle-tree = { workspace = true } @@ -33,6 +34,7 @@ reqwest = { workspace = true } lazy_static = { workspace = true } eth-trie-proofs = { workspace = true } itertools = { workspace = true } +sn-trie-proofs = { workspace = true } [features] default = [] diff --git a/hdp/src/cairo_runner/dry_run.rs b/hdp/src/cairo_runner/dry_run.rs index 4e6d64a8..f686e155 100644 --- a/hdp/src/cairo_runner/dry_run.rs +++ b/hdp/src/cairo_runner/dry_run.rs @@ -1,8 +1,8 @@ use crate::constant::DRY_CAIRO_RUN_OUTPUT_FILE; use crate::primitives::processed_types::uint256::Uint256; use crate::provider::key::{ - AccountMemorizerKey, FetchKeyEnvelope, HeaderMemorizerKey, StorageMemorizerKey, TxMemorizerKey, - TxReceiptMemorizerKey, + EvmAccountKey, EvmBlockReceiptKey, EvmBlockTxKey, EvmFetchKeyEnvelope, EvmHeaderKey, + EvmStorageKey, }; use serde::{Deserialize, Serialize}; use serde_with::serde_as; @@ -22,13 +22,13 @@ pub type DryRunResult = Vec; #[derive(Serialize, Deserialize, Debug)] pub struct DryRunnedModule { #[serde(deserialize_with = "deserialize_fetch_keys")] - pub fetch_keys: Vec, + pub fetch_keys: Vec, pub result: Uint256, #[serde_as(as = "UfeHex")] pub program_hash: Felt, } -fn deserialize_fetch_keys<'de, D>(deserializer: D) -> Result, D::Error> +fn deserialize_fetch_keys<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { @@ -45,30 +45,30 @@ where .into_iter() .map(|helper| { let envelope = match helper.key_type.as_str() { - "HeaderMemorizerKey" => { - let key: HeaderMemorizerKey = + "EvmHeaderKey" => { + let key: EvmHeaderKey = serde_json::from_value(helper.key).map_err(serde::de::Error::custom)?; - FetchKeyEnvelope::Header(key) + EvmFetchKeyEnvelope::Header(key) } - "AccountMemorizerKey" => { - let key: AccountMemorizerKey = + "EvmAccountKey" => { + let key: EvmAccountKey = serde_json::from_value(helper.key).map_err(serde::de::Error::custom)?; - FetchKeyEnvelope::Account(key) + EvmFetchKeyEnvelope::Account(key) } - "StorageMemorizerKey" => { - let key: StorageMemorizerKey = + "EvmStorageKey" => { + let key: EvmStorageKey = serde_json::from_value(helper.key).map_err(serde::de::Error::custom)?; - FetchKeyEnvelope::Storage(key) + EvmFetchKeyEnvelope::Storage(key) } - "TxMemorizerKey" => { - let key: TxMemorizerKey = + "EvmBlockTxKey" => { + let key: EvmBlockTxKey = serde_json::from_value(helper.key).map_err(serde::de::Error::custom)?; - FetchKeyEnvelope::Tx(key) + EvmFetchKeyEnvelope::Tx(key) } - "TxReceiptMemorizerKey" => { - let key: TxReceiptMemorizerKey = + "EvmBlockReceiptKey" => { + let key: EvmBlockReceiptKey = serde_json::from_value(helper.key).map_err(serde::de::Error::custom)?; - FetchKeyEnvelope::TxReceipt(key) + EvmFetchKeyEnvelope::TxReceipt(key) } _ => { return Err(serde::de::Error::custom(format!( @@ -170,10 +170,11 @@ mod tests { let result = dry_runner.run(input).unwrap(); assert_eq!(result.len(), 1); assert_eq!(result[0].fetch_keys.len(), 3); - assert_eq!(result[0].result, Uint256::from_strs("0x0", "0x0").unwrap()); + assert_eq!(result[0].result, Uint256::ZERO); assert_eq!( result[0].program_hash, - felt!("0x04df21eb479ae4416fbdc00abab6fab43bff0b8083be4d1fd8602c8fbfbd2274") + Felt::from_hex("0x04df21eb479ae4416fbdc00abab6fab43bff0b8083be4d1fd8602c8fbfbd2274") + .unwrap() ); } @@ -184,14 +185,14 @@ mod tests { { "fetch_keys": [ { - "type": "HeaderMemorizerKey", + "type": "EvmHeaderKey", "key": { "chain_id": 11155111, "block_number": 5186021 } }, { - "type": "AccountMemorizerKey", + "type": "EvmAccountKey", "key": { "chain_id": 11155111, "block_number": 5186023, @@ -199,7 +200,7 @@ mod tests { } }, { - "type": "StorageMemorizerKey", + "type": "EvmStorageKey", "key": { "chain_id": 11155111, "block_number": 5186022, @@ -233,7 +234,7 @@ mod tests { println!("Fetch key {}: {:?}", i, key); } - assert_eq!(module.result, Uint256::from_strs("0x0", "0x0").unwrap()); + assert_eq!(module.result, Uint256::ZERO); assert_eq!( module.program_hash, felt!("0xc8580f74b6e6e04d8073602ad0c0d55538b56bf8307fefebb6b65b1bbf2a27") @@ -241,15 +242,15 @@ mod tests { // Additional assertions for each key type match &module.fetch_keys[0] { - FetchKeyEnvelope::Header(key) => { + EvmFetchKeyEnvelope::Header(key) => { assert_eq!(key.chain_id, ChainId::from_numeric_id(11155111).unwrap()); assert_eq!(key.block_number, 5186021); } - _ => panic!("Expected HeaderMemorizerKey"), + _ => panic!("Expected EvmHeaderKey"), } match &module.fetch_keys[1] { - FetchKeyEnvelope::Account(key) => { + EvmFetchKeyEnvelope::Account(key) => { assert_eq!(key.chain_id, ChainId::from_numeric_id(11155111).unwrap()); assert_eq!(key.block_number, 5186023); assert_eq!( @@ -257,11 +258,11 @@ mod tests { Address::from_str("0x13CB6AE34A13a0977F4d7101eBc24B87Bb23F0d5").unwrap() ); } - _ => panic!("Expected AccountMemorizerKey"), + _ => panic!("Expected EvmAccountKey"), } match &module.fetch_keys[2] { - FetchKeyEnvelope::Storage(key) => { + EvmFetchKeyEnvelope::Storage(key) => { assert_eq!(key.chain_id, ChainId::from_numeric_id(11155111).unwrap()); assert_eq!(key.block_number, 5186022); assert_eq!( @@ -276,7 +277,7 @@ mod tests { .unwrap() ); } - _ => panic!("Expected StorageMemorizerKey"), + _ => panic!("Expected EvmStorageKey"), } } } diff --git a/hdp/src/lib.rs b/hdp/src/lib.rs index 0c64bec9..ac51f953 100644 --- a/hdp/src/lib.rs +++ b/hdp/src/lib.rs @@ -1,3 +1,8 @@ +//! The Data Processor CLI serves as an essential tool for developers working with Cairo programs and zkVM environments. +//! Its primary function is to translate human-readable requests into a format compatible with Cairo programs, +//! enabling commands to be executed over the Cairo VM and generating executable outputs. +//! This transformation is a crucial preprocessing step that prepares data for off-chain computations in zkVM environments. + pub mod cairo_runner; pub mod constant; pub mod hdp_run; diff --git a/hdp/src/preprocessor/compile/datalake.rs b/hdp/src/preprocessor/compile/datalake.rs index b3b8b4c9..27884b70 100644 --- a/hdp/src/preprocessor/compile/datalake.rs +++ b/hdp/src/preprocessor/compile/datalake.rs @@ -10,30 +10,46 @@ impl Compilable for DatalakeCompute { &self, compile_config: &CompilerConfig, ) -> Result { + // Log the target datalake task being processed info!("target task: {:#?}", self); - // ========== datalake ============== + + // ========== Fetch Provider Configuration ============== + // Retrieve the provider configuration for the specific chain ID of the datalake + let chain_id = self.datalake.get_chain_id(); let target_provider_config = compile_config .provider_config - .get(&self.datalake.get_chain_id()) + .get(&chain_id) .expect("target task's chain had not been configured."); + + // Create a new provider instance from the configuration let provider = new_provider_from_config(target_provider_config); + + // ========== Fetch Proofs ============== + // Fetch the proofs from the provider for the given datalake task let compiled_block_sampled = provider.fetch_proofs(self).await?; debug!("values to aggregate : {:#?}", compiled_block_sampled.values); - // ========== compute ============== - let aggregation_fn = &self.compute.aggregate_fn_id; - let fn_context = &self.compute.aggregate_fn_ctx; - let aggregated_result = - aggregation_fn.operation(&compiled_block_sampled.values, Some(fn_context.clone()))?; - - Ok(CompilationResult::new( + // ========== Compute Aggregated Result ============== + // Get the aggregation function and its context from the datalake compute + let aggregation_function = &self.compute.aggregate_fn_id; + let function_context = &self.compute.aggregate_fn_ctx; + + // Compute the aggregated result using the fetched values and context + let aggregated_result = aggregation_function.operation( + &compiled_block_sampled.values, + Some(function_context.clone()), + )?; + + // ========== Return Compilation Result ============== + // Return the compilation result, which is specific to a single chain context + Ok(CompilationResult::from_single_chain( + chain_id.to_numeric_id(), vec![aggregated_result], - compiled_block_sampled.headers, + compiled_block_sampled.mmr_with_headers, compiled_block_sampled.accounts, compiled_block_sampled.storages, compiled_block_sampled.transactions, compiled_block_sampled.transaction_receipts, - compiled_block_sampled.mmr_metas, )) } } @@ -140,14 +156,18 @@ mod tests { .compile(&compiler_config) .await .unwrap(); - assert_eq!(results.headers.len(), 16); - assert_eq!(results.accounts.len(), 2); - assert_eq!(results.storages.len(), 1); + // assert_eq!(results.mmr_with_headers[0].headers.len(), 16); + let account_proofs = results.accounts.iter().next().unwrap(); + assert_eq!(account_proofs.1.len(), 2); let storage_proofs = results.storages.iter().next().unwrap(); + assert_eq!(storage_proofs.1.len(), 1); + let storage_proofs = storage_proofs.1.iter().next().unwrap(); assert_eq!(storage_proofs.proofs.len(), 6); - assert_eq!(results.transactions.len(), 0); - assert_eq!(results.transaction_receipts.len(), 0); - assert_eq!(results.mmr_metas.len(), 1); + let tx_proofs = results.transactions.iter().next().unwrap(); + assert_eq!(tx_proofs.1.len(), 0); + let tx_receipt_proofs = results.transaction_receipts.iter().next().unwrap(); + assert_eq!(tx_receipt_proofs.1.len(), 0); + // assert_eq!(results.mmr_metas.len(), 1); } #[tokio::test] @@ -164,7 +184,7 @@ mod tests { start_index: 0, end_index: 10, increment: 1, - included_types: IncludedTypes::from(&[1, 1, 1, 1]), + included_types: IncludedTypes::ALL, sampled_property: TransactionsCollection::Transactions( TransactionField::GasLimit, ), @@ -178,7 +198,7 @@ mod tests { start_index: 0, end_index: 11, increment: 1, - included_types: IncludedTypes::from(&[1, 1, 1, 1]), + included_types: IncludedTypes::ALL, sampled_property: TransactionsCollection::TranasactionReceipts( TransactionReceiptField::Success, ), @@ -192,11 +212,16 @@ mod tests { .compile(&compiler_config) .await .unwrap(); - assert_eq!(results.headers.len(), 2); - assert_eq!(results.accounts.len(), 0); - assert_eq!(results.storages.len(), 0); - assert_eq!(results.transactions.len(), 10); - assert_eq!(results.transaction_receipts.len(), 11); - assert_eq!(results.mmr_metas.len(), 1); + + // assert_eq!(results.headers.len(), 2); + let accounts_proofs = results.accounts.iter().next().unwrap(); + assert_eq!(accounts_proofs.1.len(), 0); + let storages_proofs = results.storages.iter().next().unwrap(); + assert_eq!(storages_proofs.1.len(), 0); + let tx_proofs = results.transactions.iter().next().unwrap(); + assert_eq!(tx_proofs.1.len(), 10); + let tx_receipt_proofs = results.transaction_receipts.iter().next().unwrap(); + assert_eq!(tx_receipt_proofs.1.len(), 11); + // assert_eq!(results.mmr_metas.len(), 1); } } diff --git a/hdp/src/preprocessor/compile/mod.rs b/hdp/src/preprocessor/compile/mod.rs index ca5eff89..33ff0e61 100644 --- a/hdp/src/preprocessor/compile/mod.rs +++ b/hdp/src/preprocessor/compile/mod.rs @@ -1,13 +1,16 @@ use alloy::primitives::U256; - use config::CompilerConfig; +use std::hash::Hash; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use thiserror::Error; +use crate::primitives::processed_types::block_proofs::{ + convert_to_mmr_with_headers, mmr_with_header_vec_to_map, MMRWithHeader, ProcessedBlockProofs, +}; use crate::primitives::processed_types::{ - account::ProcessedAccount, header::ProcessedHeader, mmr::MMRMeta, receipt::ProcessedReceipt, - storage::ProcessedStorage, transaction::ProcessedTransaction, + account::ProcessedAccount, receipt::ProcessedReceipt, storage::ProcessedStorage, + transaction::ProcessedTransaction, }; use crate::provider::error::ProviderError; @@ -54,49 +57,141 @@ pub trait Compilable { pub struct CompilationResult { /// results of tasks pub task_results: Vec, - /// Headers related to the datalake - pub headers: HashSet, + /// mmr_with_headers related to the datalake + pub mmr_with_headers: HashMap>, /// Accounts related to the datalake - pub accounts: HashSet, + pub accounts: HashMap>, /// Storages related to the datalake - pub storages: HashSet, + pub storages: HashMap>, /// Transactions related to the datalake - pub transactions: HashSet, + pub transactions: HashMap>, /// Transaction receipts related to the datalake - pub transaction_receipts: HashSet, - /// MMR meta data related to the headers - pub mmr_metas: HashSet, + pub transaction_receipts: HashMap>, } impl CompilationResult { pub fn new( task_results: Vec, - headers: HashSet, - accounts: HashSet, - storages: HashSet, - transactions: HashSet, - transaction_receipts: HashSet, - mmr_metas: HashSet, + mmr_with_headers: HashMap>, + accounts: HashMap>, + storages: HashMap>, + transactions: HashMap>, + transaction_receipts: HashMap>, ) -> Self { Self { task_results, - headers, + mmr_with_headers, accounts, storages, transactions, transaction_receipts, - mmr_metas, } } - /// Extend the current compilation results with another compilation results + pub fn from_single_chain( + chain_id: u128, + task_results: Vec, + + mmr_with_headers: HashSet, + accounts: HashSet, + storages: HashSet, + transactions: HashSet, + transaction_receipts: HashSet, + ) -> Self { + Self { + task_results, + mmr_with_headers: HashMap::from_iter(vec![(chain_id, mmr_with_headers)]), + accounts: HashMap::from_iter(vec![(chain_id, accounts)]), + storages: HashMap::from_iter(vec![(chain_id, storages)]), + transactions: HashMap::from_iter(vec![(chain_id, transactions)]), + transaction_receipts: HashMap::from_iter(vec![(chain_id, transaction_receipts)]), + } + } + pub fn extend(&mut self, other: CompilationResult) { - self.headers.extend(other.headers); - self.accounts.extend(other.accounts); - self.storages.extend(other.storages); - self.transactions.extend(other.transactions); - self.transaction_receipts.extend(other.transaction_receipts); self.task_results.extend(other.task_results); - self.mmr_metas.extend(other.mmr_metas); + + // Merge mmr_with_headers + merge_header_mmr_maps(&mut self.mmr_with_headers, other.mmr_with_headers); + + // Merge accounts + merge_hash_maps(&mut self.accounts, other.accounts); + + // Merge storages + merge_hash_maps(&mut self.storages, other.storages); + + // Merge transactions + merge_hash_maps(&mut self.transactions, other.transactions); + + // Merge transaction_receipts + merge_hash_maps(&mut self.transaction_receipts, other.transaction_receipts); + } + + pub fn to_processed_block_vec(self) -> Vec { + let mut processed_block_vec = Vec::new(); + + for (chain_id, mmr_with_headers) in self.mmr_with_headers { + let accounts = self.accounts.get(&chain_id).cloned().unwrap_or_default(); + let storages = self.storages.get(&chain_id).cloned().unwrap_or_default(); + let transactions = self + .transactions + .get(&chain_id) + .cloned() + .unwrap_or_default(); + let transaction_receipts = self + .transaction_receipts + .get(&chain_id) + .cloned() + .unwrap_or_default(); + + let processed_block = ProcessedBlockProofs { + chain_id, + mmr_with_headers: mmr_with_headers.into_iter().collect(), + accounts: accounts.into_iter().collect(), + storages: storages.into_iter().collect(), + transactions: transactions.into_iter().collect(), + transaction_receipts: transaction_receipts.into_iter().collect(), + }; + + processed_block_vec.push(processed_block); + } + + processed_block_vec + } +} + +// Helper function to merge HashMaps with HashSet values +fn merge_hash_maps(base: &mut HashMap>, other: HashMap>) +where + T: Eq + Hash + Clone, +{ + for (key, value) in other { + base.entry(key).or_default().extend(value); + } +} + +// TODO too complicated. refactor with method in MMRWithHeader +fn merge_header_mmr_maps( + base: &mut HashMap>, + other: HashMap>, +) { + for (key, other_headers) in other { + base.entry(key) + .and_modify(|base_headers| { + // Merge using the extend method from MMRWithHeader + let mut new_headers = + mmr_with_header_vec_to_map(base_headers.iter().cloned().collect::>()); + for item in other_headers.clone() { + new_headers + .entry(item.mmr_meta) + .and_modify(|existing_headers| { + existing_headers.extend(item.headers.iter().cloned()); + }) + .or_insert_with(|| item.headers.into_iter().collect()); + } + let new_headers_vec = convert_to_mmr_with_headers(new_headers); + *base_headers = HashSet::from_iter(new_headers_vec); + }) + .or_insert(other_headers); } } diff --git a/hdp/src/preprocessor/compile/module.rs b/hdp/src/preprocessor/compile/module.rs index 1648a24a..9742823c 100644 --- a/hdp/src/preprocessor/compile/module.rs +++ b/hdp/src/preprocessor/compile/module.rs @@ -10,7 +10,7 @@ use crate::provider::key::categorize_fetch_keys; use crate::provider::traits::new_provider_from_config; use core::panic; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::path::PathBuf; use tracing::info; @@ -24,48 +24,55 @@ impl Compilable for ModuleVec { &self, compile_config: &CompilerConfig, ) -> Result { + // Log the target task for debugging purposes info!("target task: {:#?}", self[0].task); let dry_run_program_path = compile_config.dry_run_program_path.clone(); - let input = generate_input(self.to_vec(), PathBuf::from(DRY_CAIRO_RUN_OUTPUT_FILE)).await?; + // Generate input for the dry run based on the extended modules + let dry_run_input = + generate_input(self.to_vec(), PathBuf::from(DRY_CAIRO_RUN_OUTPUT_FILE)).await?; let input_string = - serde_json::to_string_pretty(&input).expect("Failed to serialize module class"); + serde_json::to_string_pretty(&dry_run_input).expect("Failed to serialize module class"); - // 2. run the dry run and get the fetch points + // 2. Run the dry run and retrieve the fetch points info!("2. Running dry-run... "); - let keys: DryRunResult = cairo_dry_run( + let dry_run_results: DryRunResult = cairo_dry_run( dry_run_program_path, input_string, compile_config.save_fetch_keys_file.clone(), )?; - if keys[0].program_hash != self[0].task.program_hash { + // Check if the program hash matches the expected hash + if dry_run_results[0].program_hash != self[0].task.program_hash { return Err(CompileError::ClassHashMismatch); } - if keys.len() != 1 { + // Ensure only one module is supported + if dry_run_results.len() != 1 { panic!("Multiple Modules are not supported"); } - let dry_runned_module = keys.into_iter().next().unwrap(); - let commit_results_maps = vec![dry_runned_module.result.to_combined_string().into()]; + // Extract the dry run module result + let dry_run_module = dry_run_results.into_iter().next().unwrap(); + let commit_results = vec![dry_run_module.result.into()]; - // 3. call provider using keys - let keys_maps_chain = categorize_fetch_keys(dry_runned_module.fetch_keys); - if keys_maps_chain.len() > 1 { - // TODO: This is temporary solution. Need to handle multiple chain id in future - panic!("Multiple chain id is not supported yet"); + // 3. Categorize fetch keys by chain ID + let categorized_keys = categorize_fetch_keys(dry_run_module.fetch_keys); + if categorized_keys.len() > 1 { + // TODO: This is a temporary solution. Need to handle multiple chain IDs in the future + panic!("Multiple chain IDs are not supported yet"); } - let mut headers = HashSet::new(); - let mut accounts = HashSet::new(); - let mut storages = HashSet::new(); - let mut transactions = HashSet::new(); - let mut transaction_receipts = HashSet::new(); - let mut mmr_metas = HashSet::new(); + // Initialize maps to store fetched proofs grouped by chain ID + let mut accounts_map = HashMap::new(); + let mut storages_map = HashMap::new(); + let mut transactions_map = HashMap::new(); + let mut transaction_receipts_map = HashMap::new(); + let mut mmr_header_map = HashMap::new(); info!("3. Fetching proofs from provider..."); - for (chain_id, keys) in keys_maps_chain { + // Loop through each chain ID and fetch proofs + for (chain_id, keys) in categorized_keys { info!("target provider chain id: {}", chain_id); let target_provider_config = compile_config .provider_config @@ -74,23 +81,37 @@ impl Compilable for ModuleVec { let provider = new_provider_from_config(target_provider_config); let results = provider.fetch_proofs_from_keys(keys).await?; - // TODO: can we do better? - headers.extend(results.headers.into_iter()); - accounts.extend(results.accounts.into_iter()); - storages.extend(results.storages.into_iter()); - transactions.extend(results.transactions.into_iter()); - transaction_receipts.extend(results.transaction_receipts.into_iter()); - mmr_metas.extend(results.mmr_metas.into_iter()); + // Update the maps with fetched results + mmr_header_map.insert( + chain_id.to_numeric_id(), + HashSet::from_iter(results.mmr_with_headers.into_iter()), + ); + accounts_map.insert( + chain_id.to_numeric_id(), + HashSet::from_iter(results.accounts.into_iter()), + ); + storages_map.insert( + chain_id.to_numeric_id(), + HashSet::from_iter(results.storages.into_iter()), + ); + transactions_map.insert( + chain_id.to_numeric_id(), + HashSet::from_iter(results.transactions.into_iter()), + ); + transaction_receipts_map.insert( + chain_id.to_numeric_id(), + HashSet::from_iter(results.transaction_receipts.into_iter()), + ); } + // Create and return the compilation result containing all relevant proofs let compiled_result = CompilationResult::new( - commit_results_maps, - headers, - accounts, - storages, - transactions, - transaction_receipts, - mmr_metas, + commit_results, + mmr_header_map, + accounts_map, + storages_map, + transactions_map, + transaction_receipts_map, ); Ok(compiled_result) } diff --git a/hdp/src/preprocessor/mod.rs b/hdp/src/preprocessor/mod.rs index 004f31e7..bcfdb901 100644 --- a/hdp/src/preprocessor/mod.rs +++ b/hdp/src/preprocessor/mod.rs @@ -3,7 +3,6 @@ use crate::constant::SOUND_CAIRO_RUN_OUTPUT_FILE; use crate::primitives::merkle_tree::{build_result_merkle_tree, build_task_merkle_tree}; -use crate::primitives::processed_types::block_proofs::ProcessedBlockProofs; use crate::primitives::processed_types::datalake_compute::ProcessedDatalakeCompute; use crate::primitives::processed_types::module::ProcessedModule; use crate::primitives::processed_types::query::ProcessorInput; @@ -123,14 +122,8 @@ impl PreProcessor { } } - let proofs = ProcessedBlockProofs { - mmr_metas: Vec::from_iter(compiled_results.mmr_metas), - headers: Vec::from_iter(compiled_results.headers), - accounts: Vec::from_iter(compiled_results.accounts), - storages: Vec::from_iter(compiled_results.storages), - transactions: Vec::from_iter(compiled_results.transactions), - transaction_receipts: Vec::from_iter(compiled_results.transaction_receipts), - }; + // TODO: this chain id need to be fix + let proofs = compiled_results.to_processed_block_vec(); let processed_result = ProcessorInput::new( SOUND_CAIRO_RUN_OUTPUT_FILE.into(), result_merkle_tree.root(), diff --git a/hdp/src/preprocessor/module_registry.rs b/hdp/src/preprocessor/module_registry.rs index 8bcc4e29..5672db37 100644 --- a/hdp/src/preprocessor/module_registry.rs +++ b/hdp/src/preprocessor/module_registry.rs @@ -14,7 +14,6 @@ use crate::{ }, }; use reqwest::Client; - use std::{path::PathBuf, str::FromStr}; use thiserror::Error; use tracing::info; @@ -65,7 +64,9 @@ impl ModuleRegistry { local_class_path: Option, module_inputs: Vec, ) -> Result { - let program_hash = program_hash.map(|program_hash| Felt::from_hex(&program_hash).unwrap()); + let program_hash = program_hash.map(|program_hash| { + Felt::from_hex(&program_hash).expect("program hash cannot be converted to FieldElement") + }); let module_inputs: Result, _> = module_inputs .into_iter() .map(|input| ModuleInput::from_str(&input)) diff --git a/hdp/src/primitives/block/account.rs b/hdp/src/primitives/block/account.rs index ff181092..73cf4237 100644 --- a/hdp/src/primitives/block/account.rs +++ b/hdp/src/primitives/block/account.rs @@ -28,7 +28,7 @@ impl Account { } pub fn rlp_decode(mut rlp: &[u8]) -> Self { - ::decode(&mut rlp).unwrap() + ::decode(&mut rlp).expect("rlp decode failed.") } } @@ -47,18 +47,15 @@ impl From<&EIP1186AccountProofResponse> for Account { mod tests { use super::*; use alloy::hex; - use alloy::primitives::U256; - use std::str::FromStr; + use alloy::primitives::{b256, U256}; #[test] fn test_get_account_rlp() { let account = Account::new( 1, U256::from(0), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -69,10 +66,8 @@ mod tests { let account = Account::new( 2, U256::from(0), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -83,10 +78,8 @@ mod tests { let account = Account::new( 2, U256::from(0x1), - B256::from_str("0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185") - .unwrap(), - B256::from_str("0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") - .unwrap(), + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c"), ); let account_rlp = account.rlp_encode(); assert_eq!( @@ -104,14 +97,8 @@ mod tests { Account::new( 1, U256::from(0), - B256::from_str( - "0x1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185" - ) - .unwrap(), - B256::from_str( - "0xcd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c" - ) - .unwrap() + b256!("1c35dfde2b62d99d3a74fda76446b60962c4656814bdd7815eb6e5b8be1e7185"), + b256!("cd4f25236fff0ccac15e82bf4581beb08e95e1b5ba89de6031c75893cd91245c") ) ); } diff --git a/hdp/src/primitives/block/header.rs b/hdp/src/primitives/block/header.rs index ea7c6343..2218e957 100644 --- a/hdp/src/primitives/block/header.rs +++ b/hdp/src/primitives/block/header.rs @@ -131,7 +131,6 @@ impl Header { } /// Heavy function that will calculate hash of data and will *not* save the change to metadata. - /// Use [`Header::seal`], [`SealedHeader`] and unlock if you need hash to be persistent. pub fn hash_slow(&self) -> B256 { keccak256(alloy_rlp::encode(self)) } @@ -343,7 +342,7 @@ impl Header { } /// Block header returned from RPC -/// https://ethereum.org/en/developers/docs/apis/json-rpc#eth_getblockbynumber +/// #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct BlockHeaderFromRpc { @@ -378,8 +377,8 @@ impl BlockHeaderFromRpc { } } -impl From<&BlockHeaderFromRpc> for Header { - fn from(value: &BlockHeaderFromRpc) -> Self { +impl From for Header { + fn from(value: BlockHeaderFromRpc) -> Self { Self { parent_hash: B256::from_str(&value.parent_hash).expect("Invalid hex string"), ommers_hash: B256::from_str(&value.sha3_uncles).expect("Invalid hex string"), @@ -400,23 +399,18 @@ impl From<&BlockHeaderFromRpc> for Header { nonce: u64::from_str_radix(&value.nonce[2..], 16).expect("Invalid hex string"), base_fee_per_gas: value .base_fee_per_gas - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), withdrawals_root: value .withdrawals_root - .clone() .map(|x| B256::from_str(&x).expect("Invalid hex string")), blob_gas_used: value .blob_gas_used - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), excess_blob_gas: value .excess_blob_gas - .clone() .map(|x| u64::from_str_radix(&x[2..], 16).expect("Invalid hex string")), parent_beacon_block_root: value .parent_beacon_block_root - .clone() .map(|x| B256::from_str(&x).expect("Invalid hex string")), } } diff --git a/hdp/src/primitives/processed_types/block_proofs.rs b/hdp/src/primitives/processed_types/block_proofs.rs index a0e8f406..a19ce135 100644 --- a/hdp/src/primitives/processed_types/block_proofs.rs +++ b/hdp/src/primitives/processed_types/block_proofs.rs @@ -1,3 +1,5 @@ +use std::collections::{HashMap, HashSet}; + use serde::{Deserialize, Serialize}; use super::{ @@ -7,12 +9,79 @@ use super::{ /// Provider should fetch all the proofs and rlp values from given keys. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct ProcessedBlockProofs { - pub mmr_metas: Vec, - pub headers: Vec, + pub chain_id: u128, + pub mmr_with_headers: Vec, pub accounts: Vec, pub storages: Vec, pub transactions: Vec, pub transaction_receipts: Vec, } + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] +pub struct MMRWithHeader { + pub mmr_meta: MMRMeta, + pub headers: Vec, +} + +pub fn mmr_with_header_vec_to_map( + target: Vec, +) -> HashMap> { + let mut map = HashMap::new(); + for target_item in target { + map.entry(target_item.mmr_meta) + .and_modify(|existing_headers: &mut HashSet| { + existing_headers.extend(target_item.headers.iter().cloned()); + }) + .or_insert_with(|| target_item.headers.into_iter().collect()); + } + map +} + +impl MMRWithHeader { + pub fn to_map(self) -> HashMap> { + let mut map = HashMap::new(); + map.insert(self.mmr_meta, HashSet::from_iter(self.headers)); + map + } + + pub fn extend(self, other: MMRWithHeader) -> Vec { + let mut self_map = self.to_map(); + let other_map = other.to_map(); + for (mmr, headers) in other_map { + self_map + .entry(mmr) + .and_modify(|existing_headers| { + existing_headers.extend(headers.iter().cloned()); + }) + .or_insert_with(|| headers.into_iter().collect()); + } + convert_to_mmr_with_headers(self_map) + } +} + +pub fn convert_to_mmr_with_headers( + map: HashMap>, +) -> Vec { + map.into_iter() + .map(|(mmr_meta, headers)| MMRWithHeader { + mmr_meta, + headers: headers.into_iter().collect(), + }) + .collect() +} + +pub fn convert_to_mmr_meta_set( + mmr_with_headers: Vec, +) -> HashMap> { + mmr_with_headers + .into_iter() + .map(|mmr_with_header| { + ( + mmr_with_header.mmr_meta, + mmr_with_header.headers.into_iter().collect::>(), + ) + }) + .collect() +} diff --git a/hdp/src/primitives/processed_types/cairo_format/account.rs b/hdp/src/primitives/processed_types/cairo_format/account.rs index 53147d64..5c8f4827 100644 --- a/hdp/src/primitives/processed_types/cairo_format/account.rs +++ b/hdp/src/primitives/processed_types/cairo_format/account.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use crate::primitives::processed_types::account::ProcessedAccount as BaseProcessedAccount; @@ -14,8 +14,7 @@ impl AsCairoFormat for BaseProcessedAccount { type Output = ProcessedAccount; fn as_cairo_format(&self) -> Self::Output { - let address_chunk_result = - FieldElementVectorUnit::from_bytes(self.address.as_ref()).unwrap(); + let address_chunk_result = FieldElementVectorUnit::from_bytes(self.address.as_ref()); let account_key = &self.account_key; let proofs = self .proofs diff --git a/hdp/src/primitives/processed_types/cairo_format/block_proofs.rs b/hdp/src/primitives/processed_types/cairo_format/block_proofs.rs index c7f6ee13..f5917c5e 100644 --- a/hdp/src/primitives/processed_types/cairo_format/block_proofs.rs +++ b/hdp/src/primitives/processed_types/cairo_format/block_proofs.rs @@ -14,11 +14,18 @@ impl AsCairoFormat for BaseProcessedBlockProofs { fn as_cairo_format(&self) -> Self::Output { ProcessedBlockProofs { - mmr_metas: self.mmr_metas.clone(), - headers: self - .headers + chain_id: self.chain_id, + mmr_with_headers: self + .mmr_with_headers .iter() - .map(|header| header.as_cairo_format()) + .map(|mmr_with_header| MMRWithHeader { + mmr_meta: mmr_with_header.mmr_meta.clone(), + headers: mmr_with_header + .headers + .iter() + .map(|header| header.as_cairo_format()) + .collect(), + }) .collect(), accounts: self .accounts @@ -46,10 +53,16 @@ impl AsCairoFormat for BaseProcessedBlockProofs { #[derive(Serialize, Deserialize)] pub struct ProcessedBlockProofs { - pub mmr_metas: Vec, - pub headers: Vec, + pub chain_id: u128, + pub mmr_with_headers: Vec, pub accounts: Vec, pub storages: Vec, pub transactions: Vec, pub transaction_receipts: Vec, } + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct MMRWithHeader { + pub mmr_meta: MMRMeta, + pub headers: Vec, +} diff --git a/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs b/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs index c6718a1e..b85e479b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs +++ b/hdp/src/primitives/processed_types/cairo_format/datalake_compute.rs @@ -4,15 +4,14 @@ use super::{felt_vec_unit::FieldElementVectorUnit, traits::AsCairoFormat}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; impl AsCairoFormat for BaseProcessedDatalakeCompute { type Output = ProcessedDatalakeCompute; fn as_cairo_format(&self) -> Self::Output { - let computational_task_felts = - FieldElementVectorUnit::from_bytes(&self.encoded_task).unwrap(); - let datalake_felts = FieldElementVectorUnit::from_bytes(&self.encoded_datalake).unwrap(); + let computational_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task); + let datalake_felts = FieldElementVectorUnit::from_bytes(&self.encoded_datalake); ProcessedDatalakeCompute { task_bytes_len: computational_task_felts.bytes_len, encoded_task: computational_task_felts.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs b/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs index 99d48b58..0c4902e7 100644 --- a/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs +++ b/hdp/src/primitives/processed_types/cairo_format/felt_vec_unit.rs @@ -1,21 +1,30 @@ -use anyhow::Result; use serde::Serialize; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; #[serde_as] #[derive(Serialize, Debug)] pub struct FieldElementVectorUnit { + /// Chunked vector of field elements #[serde_as(as = "Vec")] pub felts: Vec, + /// Length of the original byte array before chunking into field elements pub bytes_len: u64, } impl FieldElementVectorUnit { - pub fn from_bytes(bytes: &[u8]) -> Result { + /// Converts a byte slice into a `FieldElementVectorUnit`. + /// + /// This function takes a slice of bytes and converts it into a `FieldElementVectorUnit`, + /// which consists of a vector of [`Felt`]s and the length of the original byte slice. + /// + /// # Panics + /// + /// This function will panic if the input byte slice is empty. + pub fn from_bytes(bytes: &[u8]) -> Self { if bytes.is_empty() { - return Err(anyhow::anyhow!("Empty hex input")); + panic!("Cannot convert to FieldElementVectorUnit from empty bytes") } let bytes_len = bytes.len() as u64; let felts = bytes @@ -29,7 +38,7 @@ impl FieldElementVectorUnit { }) .collect(); - Ok(Self { felts, bytes_len }) + Self { felts, bytes_len } } } @@ -40,16 +49,16 @@ mod tests { use super::*; #[test] + #[should_panic(expected = "Cannot convert to FieldElementVectorUnit from empty bytes")] fn test_empty_bytes() { let bytes = hex::decode("").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes); - assert!(result.is_err()); + FieldElementVectorUnit::from_bytes(&bytes); } #[test] fn test_single_byte_bytes() { let bytes = hex::decode("0x01").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 1); assert_eq!(result.felts.len(), 1); assert_eq!(result.felts[0], Felt::from_hex("0x1").unwrap()); @@ -58,7 +67,7 @@ mod tests { #[test] fn test_single_chunk_bytes() { let bytes = hex::decode("0x1234567890abcdef").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 8); assert_eq!(result.felts.len(), 1); assert_eq!(result.felts[0], Felt::from_hex("efcdab9078563412").unwrap()); @@ -67,7 +76,7 @@ mod tests { #[test] fn test_multiple_chunks_bytes() { let bytes = hex::decode("0x1234567890abcdef1122334455667788").unwrap(); - let result = FieldElementVectorUnit::from_bytes(&bytes).unwrap(); + let result = FieldElementVectorUnit::from_bytes(&bytes); assert_eq!(result.bytes_len, 16); assert_eq!(result.felts.len(), 2); assert_eq!(result.felts[0], Felt::from_hex("efcdab9078563412").unwrap()); diff --git a/hdp/src/primitives/processed_types/cairo_format/header.rs b/hdp/src/primitives/processed_types/cairo_format/header.rs index 20734910..395e8e5b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/header.rs +++ b/hdp/src/primitives/processed_types/cairo_format/header.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use crate::primitives::processed_types::header::{ ProcessedHeader as BaseProcessedHeader, ProcessedHeaderProof as BasedProcessedHeaderProof, @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedHeader { type Output = ProcessedHeader; fn as_cairo_format(&self) -> Self::Output { - let felts_unit = FieldElementVectorUnit::from_bytes(&self.rlp).unwrap(); + let felts_unit = FieldElementVectorUnit::from_bytes(&self.rlp); let proof = self.proof.clone(); ProcessedHeader { rlp: felts_unit.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/module.rs b/hdp/src/primitives/processed_types/cairo_format/module.rs index 548efc0c..b0c1df9a 100644 --- a/hdp/src/primitives/processed_types/cairo_format/module.rs +++ b/hdp/src/primitives/processed_types/cairo_format/module.rs @@ -5,7 +5,7 @@ use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use super::{AsCairoFormat, FieldElementVectorUnit}; @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedModule { type Output = ProcessedModule; fn as_cairo_format(&self) -> Self::Output { - let module_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task).unwrap(); + let module_task_felts = FieldElementVectorUnit::from_bytes(&self.encoded_task); ProcessedModule { module_class: self.module_class.clone(), encoded_task: module_task_felts.felts, diff --git a/hdp/src/primitives/processed_types/cairo_format/mpt.rs b/hdp/src/primitives/processed_types/cairo_format/mpt.rs index 8cc20158..93fcc4f5 100644 --- a/hdp/src/primitives/processed_types/cairo_format/mpt.rs +++ b/hdp/src/primitives/processed_types/cairo_format/mpt.rs @@ -4,7 +4,7 @@ use super::{felt_vec_unit::FieldElementVectorUnit, traits::AsCairoFormat}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; impl AsCairoFormat for BaseProcessedMPTProof { type Output = ProcessedMPTProof; @@ -13,7 +13,7 @@ impl AsCairoFormat for BaseProcessedMPTProof { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/cairo_format/query.rs b/hdp/src/primitives/processed_types/cairo_format/query.rs index 228e7043..e26ec1cd 100644 --- a/hdp/src/primitives/processed_types/cairo_format/query.rs +++ b/hdp/src/primitives/processed_types/cairo_format/query.rs @@ -15,7 +15,11 @@ impl AsCairoFormat for BasedProcessorInput { cairo_run_output_path: self.cairo_run_output_path.clone(), task_root: self.tasks_root, result_root: self.results_root, - proofs: self.proofs.as_cairo_format(), + proofs: self + .proofs + .iter() + .map(|proof| proof.as_cairo_format()) + .collect(), tasks: self .tasks .iter() @@ -34,7 +38,7 @@ pub struct ProcessorInput { /// Batched results root of all tasks. pub result_root: B256, /// Fetched proofs per each fetch point. - pub proofs: ProcessedBlockProofs, + pub proofs: Vec, /// tasks to be executed. pub tasks: Vec, } diff --git a/hdp/src/primitives/processed_types/cairo_format/receipt.rs b/hdp/src/primitives/processed_types/cairo_format/receipt.rs index 7df7cdf5..b09ebd59 100644 --- a/hdp/src/primitives/processed_types/cairo_format/receipt.rs +++ b/hdp/src/primitives/processed_types/cairo_format/receipt.rs @@ -5,7 +5,7 @@ use crate::primitives::processed_types::receipt::ProcessedReceipt as BaseProcess use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; impl AsCairoFormat for BaseProcessedReceipt { type Output = ProcessedReceipt; @@ -15,7 +15,7 @@ impl AsCairoFormat for BaseProcessedReceipt { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/cairo_format/storage.rs b/hdp/src/primitives/processed_types/cairo_format/storage.rs index dce138ae..b370434b 100644 --- a/hdp/src/primitives/processed_types/cairo_format/storage.rs +++ b/hdp/src/primitives/processed_types/cairo_format/storage.rs @@ -4,7 +4,7 @@ use alloy::primitives::StorageKey; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use crate::primitives::processed_types::storage::ProcessedStorage as BaseProcessedStorage; @@ -14,9 +14,8 @@ impl AsCairoFormat for BaseProcessedStorage { type Output = ProcessedStorage; fn as_cairo_format(&self) -> Self::Output { - let address_chunk_result = - FieldElementVectorUnit::from_bytes(self.address.as_ref()).unwrap(); - let slot_chunk_result = FieldElementVectorUnit::from_bytes(self.slot.as_ref()).unwrap(); + let address_chunk_result = FieldElementVectorUnit::from_bytes(self.address.as_ref()); + let slot_chunk_result = FieldElementVectorUnit::from_bytes(self.slot.as_ref()); let storage_key = self.storage_key; let proofs = self .proofs diff --git a/hdp/src/primitives/processed_types/cairo_format/transaction.rs b/hdp/src/primitives/processed_types/cairo_format/transaction.rs index 8feb3379..80bec172 100644 --- a/hdp/src/primitives/processed_types/cairo_format/transaction.rs +++ b/hdp/src/primitives/processed_types/cairo_format/transaction.rs @@ -5,7 +5,7 @@ use crate::primitives::processed_types::transaction::ProcessedTransaction as Bas use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; impl AsCairoFormat for BaseProcessedTransaction { type Output = ProcessedTransaction; @@ -15,7 +15,7 @@ impl AsCairoFormat for BaseProcessedTransaction { let proof_felts: Vec = self .proof .iter() - .map(|proof| FieldElementVectorUnit::from_bytes(proof).unwrap()) + .map(|proof| FieldElementVectorUnit::from_bytes(proof)) .collect(); let proof_bytes_len = proof_felts.iter().map(|f| f.bytes_len).collect(); diff --git a/hdp/src/primitives/processed_types/mmr.rs b/hdp/src/primitives/processed_types/mmr.rs index 8bd1a4d3..19aef186 100644 --- a/hdp/src/primitives/processed_types/mmr.rs +++ b/hdp/src/primitives/processed_types/mmr.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::primitives::{block::header::MMRMetaFromNewIndexer, utils::hex_string_to_uint, ChainId}; +use crate::primitives::{block::header::MMRMetaFromNewIndexer, utils::hex_string_to_uint}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct MMRMeta { @@ -9,29 +9,26 @@ pub struct MMRMeta { pub size: u64, // hex encoded pub peaks: Vec, - pub chain_id: u128, } impl MMRMeta { - pub fn new(id: u64, root: String, size: u64, peaks: Vec, chain_id: u128) -> Self { + pub fn new(id: u64, root: String, size: u64, peaks: Vec) -> Self { MMRMeta { id, root, size, peaks, - chain_id, } } } impl MMRMeta { - pub fn from_indexer(val: MMRMetaFromNewIndexer, chain_id: ChainId) -> Self { + pub fn from_indexer(val: MMRMetaFromNewIndexer) -> Self { MMRMeta { id: hex_string_to_uint(&val.mmr_id), root: val.mmr_root, size: val.mmr_size, peaks: val.mmr_peaks, - chain_id: chain_id.to_numeric_id(), } } } @@ -61,7 +58,6 @@ mod tests { "0x66c82fce8bfc291095c6c9255b1f7ccf725a1e91e8ae8cd8c43ceb111c21480".to_string(), "0x2e5274895f9cd556bb8dee5b2551e9cda9aa3caa23532f9824abcc62d5ad273".to_string(), ], - 11155111, ); let processed_string = include_str!("../../../../fixtures/primitives/mmr.json"); diff --git a/hdp/src/primitives/processed_types/query.rs b/hdp/src/primitives/processed_types/query.rs index d41e3832..29ad40c3 100644 --- a/hdp/src/primitives/processed_types/query.rs +++ b/hdp/src/primitives/processed_types/query.rs @@ -3,7 +3,8 @@ use alloy::primitives::B256; use std::path::PathBuf; use super::{ - block_proofs::ProcessedBlockProofs, processor_output::ProcessorOutput, task::ProcessedTask, + block_proofs::ProcessedBlockProofs, mmr::MMRMeta, processor_output::ProcessorOutput, + task::ProcessedTask, }; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -14,7 +15,7 @@ pub struct ProcessorInput { pub tasks_root: B256, // U256 type pub results_root: B256, - pub proofs: ProcessedBlockProofs, + pub proofs: Vec, pub tasks: Vec, } @@ -23,7 +24,7 @@ impl ProcessorInput { cairo_run_output_path: PathBuf, results_root: B256, tasks_root: B256, - proofs: ProcessedBlockProofs, + proofs: Vec, tasks: Vec, ) -> Self { Self { @@ -58,6 +59,12 @@ impl ProcessorInput { .iter() .map(|task| task.get_result_proof()) .collect(); + let mmr_metas: Vec = self + .proofs + .iter() + .flat_map(|x| &x.mmr_with_headers) + .map(|mmr_with_header| mmr_with_header.mmr_meta.clone()) + .collect(); ProcessorOutput::new( task_results, @@ -67,7 +74,7 @@ impl ProcessorInput { results_inclusion_proofs, self.results_root, self.tasks_root, - self.proofs.mmr_metas.clone(), + mmr_metas, ) } } diff --git a/hdp/src/primitives/processed_types/uint256.rs b/hdp/src/primitives/processed_types/uint256.rs index d89fae8e..2fde866a 100644 --- a/hdp/src/primitives/processed_types/uint256.rs +++ b/hdp/src/primitives/processed_types/uint256.rs @@ -1,37 +1,91 @@ //! This module contains the `Uint256` type, which is a 256-bit unsigned integer. //! This is compatible with Cairo `uint256` type. -use alloy::primitives::{hex::FromHex, B256}; +use crate::primitives::utils::bytes_to_hex_string; +use alloy::primitives::{hex::FromHex, B256, U256}; use anyhow::Result; +use core::fmt::Display; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use std::str::FromStr; -use crate::primitives::utils::bytes_to_hex_string; - +/// [`Uint256`] represents a 256-bit unsigned integer. +/// It is implemented as a struct with two [`Felt`] values: `high` and `low`. +/// Each [`Felt`] represents 128 bits of the 256-bit integer. #[serde_as] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] pub struct Uint256 { #[serde_as(as = "UfeHex")] - pub low: Felt, + pub low: Felt, // Represents the least significant 128 bits #[serde_as(as = "UfeHex")] - pub high: Felt, + pub high: Felt, // Represents the most significant 128 bits +} + +impl Default for Uint256 { + /// Returns a `Uint256` with a value of zero. + fn default() -> Self { + Self::ZERO + } } impl Uint256 { - pub fn from_strs(high: &str, low: &str) -> Result { + /// Constant representing zero as a `Uint256`. + pub const ZERO: Self = Self { + high: Felt::ZERO, + low: Felt::ZERO, + }; + + /// Creates a `Uint256` from two byte slices representing the high and low parts. + /// + /// # Arguments + /// * `high` - A byte slice representing the most significant 128 bits + /// * `low` - A byte slice representing the least significant 128 bits + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_bytes_tuple(high: &[u8], low: &[u8]) -> Result { + Ok(Self { + high: Felt::from_bytes_be_slice(high), + low: Felt::from_bytes_be_slice(low), + }) + } + + /// Creates a `Uint256` from two hexadecimal strings representing the high and low parts. + /// + /// # Arguments + /// * `high` - A string slice representing the most significant 128 bits in hex + /// * `low` - A string slice representing the least significant 128 bits in hex + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_hex_tuple(high: &str, low: &str) -> Result { Ok(Self { high: Felt::from_hex(high)?, low: Felt::from_hex(low)?, }) } - pub fn from_felts(high: Felt, low: Felt) -> Self { + /// Creates a `Uint256` from two [`Felt`]s representing the high and low parts. + /// + /// # Arguments + /// * `high` - A `Felt` representing the most significant 128 bits + /// * `low` - A `Felt` representing the least significant 128 bits + /// + /// # Returns + /// A new `Uint256` instance. + pub fn from_field_element_tuple(high: Felt, low: Felt) -> Self { Self { high, low } } + /// Creates a `Uint256` from a little-endian hexadecimal string. + /// + /// # Arguments + /// * `hex_str` - A string slice containing the hexadecimal representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. pub fn from_le_hex_str(hex_str: &str) -> Result { let clean_hex = hex_str.trim_start_matches("0x"); let mut fix_hex: B256 = B256::from_hex(clean_hex)?; @@ -46,6 +100,13 @@ impl Uint256 { }) } + /// Creates a `Uint256` from a big-endian hexadecimal string. + /// + /// # Arguments + /// * `hex_str` - A string slice containing the hexadecimal representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. pub fn from_be_hex_str(hex_str: &str) -> Result { let clean_hex = hex_str.trim_start_matches("0x"); let padded_hex = format!("{:0>64}", clean_hex); @@ -56,8 +117,28 @@ impl Uint256 { }) } - /// combine_parts_into_big_endian_hex - pub fn to_combined_string(&self) -> B256 { + /// Creates a `Uint256` from a big-endian byte slice. + /// + /// # Arguments + /// * `bytes` - A byte slice containing the 256-bit integer representation + /// + /// # Returns + /// A `Result` containing the new `Uint256` or an error if conversion fails. + pub fn from_be_bytes(bytes: &[u8]) -> Result { + let high_part = bytes[..16].to_vec(); + let low_part = bytes[16..].to_vec(); + + Ok(Self { + high: Felt::from_hex(&bytes_to_hex_string(&high_part))?, + low: Felt::from_hex(&bytes_to_hex_string(&low_part))?, + }) + } +} + +impl Display for Uint256 { + /// Formats the `Uint256` as a hexadecimal string. + /// The output is a 0x-prefixed, 64-character hexadecimal string. + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Ensure both parts are exactly 32 hex characters long let high_padded = format!( "{:0>32}", @@ -71,48 +152,76 @@ impl Uint256 { ) .trim_start_matches("0x") .to_string(); + write!(f, "0x{}{}", high_padded, low_padded) + } +} - B256::from_str(&format!("0x{}{}", high_padded, low_padded)).unwrap() +impl From for B256 { + /// Converts a `Uint256` to a `B256`. + fn from(value: Uint256) -> B256 { + B256::from_str(&value.to_string()).expect("Invalid value for B256") + } +} + +impl From for Uint256 { + /// Converts a `B256` to a `Uint256`. + fn from(value: B256) -> Self { + Self::from_be_bytes(value.as_slice()).expect("Invalid value for Uint256") + } +} + +impl From for U256 { + /// Converts a `Uint256` to a `U256`. + fn from(value: Uint256) -> U256 { + U256::from_str(&value.to_string()).expect("Invalid value for U256") + } +} + +impl From for Uint256 { + /// Converts a `U256` to a `Uint256`. + fn from(value: U256) -> Self { + Self::from_be_bytes(&value.to_be_bytes_vec()).expect("Invalid value for Uint256") } } #[cfg(test)] mod tests { + use alloy::primitives::b256; use starknet::macros::felt; use super::*; #[test] fn test_combine_parts_into_big_endian_hex() { - let uint256 = Uint256::from_felts( - Felt::from_hex("0x988c19313bcbfb19fcc4da12e3adb46c").unwrap(), - Felt::from_hex("0xf6fbdd08af91b1d8df80c6e755159f1").unwrap(), - ); + let result0: B256 = Uint256::from_field_element_tuple( + felt!("0x988c19313bcbfb19fcc4da12e3adb46c"), + felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), + ) + .into(); assert_eq!( - uint256.to_combined_string(), - B256::from_str("0x988c19313bcbfb19fcc4da12e3adb46c0f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + result0, + b256!("988c19313bcbfb19fcc4da12e3adb46c0f6fbdd08af91b1d8df80c6e755159f1") ); - let uint256 = Uint256::from_felts( + let result1: B256 = Uint256::from_field_element_tuple( felt!("0x988c19313bcbfb19fcc4da12e3adb46"), felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), - ); + ) + .into(); assert_eq!( - uint256.to_combined_string(), - B256::from_str("0x0988c19313bcbfb19fcc4da12e3adb460f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + result1, + b256!("0988c19313bcbfb19fcc4da12e3adb460f6fbdd08af91b1d8df80c6e755159f1") ); - let uint256 = Uint256::from_felts( + let result2: B256 = Uint256::from_field_element_tuple( felt!("0x988c19313bcbfb19fcc4da12e3adb4"), felt!("0xf6fbdd08af91b1d8df80c6e755159f1"), - ); + ) + .into(); assert_eq!( - uint256.to_combined_string(), - B256::from_str("0x00988c19313bcbfb19fcc4da12e3adb40f6fbdd08af91b1d8df80c6e755159f1") - .unwrap() + result2, + b256!("00988c19313bcbfb19fcc4da12e3adb40f6fbdd08af91b1d8df80c6e755159f1") ); } @@ -122,12 +231,13 @@ mod tests { let result = Uint256::from_be_hex_str(hex_str).unwrap(); assert_eq!( result, - Uint256::from_felts( + Uint256::from_field_element_tuple( felt!("0x60870c80ce4e1d0c35e34f08b1648e8a"), felt!("0x4fdc7818eea7caedbd316c63a3863562"), ) ); - assert_eq!(result.to_combined_string().to_string(), hex_str); + let result_b256: B256 = result.into(); + assert_eq!(result_b256, B256::from_str(hex_str).unwrap()); } #[test] @@ -136,7 +246,7 @@ mod tests { let result = Uint256::from_le_hex_str(hex_str).unwrap(); assert_eq!( result, - Uint256::from_felts( + Uint256::from_field_element_tuple( felt!("0x1d693b26fded2cc4edb9acbf8133f52d"), felt!("0x2a32ca1db17188d788996d243adbda8d"), ) @@ -145,7 +255,7 @@ mod tests { #[test] fn test_uint256_serde() { - let target = Uint256::from_felts( + let target = Uint256::from_field_element_tuple( felt!("0x1d693b26fded2cc4edb9acbf8133f52d"), felt!("0x2a32ca1db17188d788996d243adbda8d"), ); @@ -154,4 +264,11 @@ mod tests { let expected = json_file.trim(); assert_eq!(string, expected); } + + #[test] + fn test_uint256_default() { + let zero: B256 = Uint256::ZERO.into(); + + assert_eq!(zero, B256::ZERO) + } } diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs index bf529c3a..d2f1413c 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/envelope.rs @@ -180,7 +180,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -190,7 +190,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let datalakes = vec![ @@ -215,7 +215,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -225,7 +225,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); assert_eq!( @@ -247,7 +247,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -257,7 +257,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let datalakes = vec![ @@ -282,7 +282,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); let transaction_datalake2 = TransactionsInBlockDatalake::new( @@ -292,7 +292,7 @@ mod tests { 1, 100, 1, - IncludedTypes::from(&[0, 0, 1, 1]), + IncludedTypes::from_bytes(&[0, 0, 1, 1]), ); assert_eq!( diff --git a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs index 81c91781..408ad867 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/datalake/transactions_in_block.rs @@ -7,7 +7,7 @@ use crate::primitives::{ }, ChainId, }; -use alloy::primitives::keccak256; +use alloy::primitives::{keccak256, U256}; use alloy::{ dyn_abi::{DynSolType, DynSolValue}, primitives::B256, @@ -29,7 +29,8 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { let start_index: DynSolValue = self.start_index.into(); let end_index: DynSolValue = self.end_index.into(); let increment: DynSolValue = self.increment.into(); - let included_types: DynSolValue = self.included_types.to_uint256().into(); + let converted: U256 = self.included_types.into(); + let included_types: DynSolValue = converted.into(); let tuple_value = DynSolValue::Tuple(vec![ datalake_code, @@ -48,13 +49,13 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { } } - /// Get the commitment hash of the [`TransactionsDatalake`] + /// Get the commitment hash of the [`TransactionsInBlockDatalake`] fn commit(&self) -> B256 { let encoded_datalake = self.encode().expect("Encoding failed"); keccak256(encoded_datalake) } - /// Decode the encoded transactions datalake hex string into a [`TransactionsDatalake`] + /// Decode the encoded transactions datalake hex string into a [`TransactionsInBlockDatalake`] fn decode(encoded: &[u8]) -> Result { let abi_type: DynSolType = "(uint256,uint256, uint256, uint256, uint256, uint256, uint256, bytes)".parse()?; @@ -73,7 +74,7 @@ impl DatalakeCodecs for TransactionsInBlockDatalake { let start_index = value[3].as_uint().unwrap().0.to_string().parse::()?; let end_index = value[4].as_uint().unwrap().0.to_string().parse::()?; let increment = value[5].as_uint().unwrap().0.to_string().parse::()?; - let included_types = IncludedTypes::from_uint256(value[6].as_uint().unwrap().0); + let included_types = IncludedTypes::from(value[6].as_uint().unwrap().0); let sampled_property = TransactionsCollection::deserialize(value[7].as_bytes().unwrap())?; Ok(Self { diff --git a/hdp/src/primitives/solidity_types/datalake_compute/mod.rs b/hdp/src/primitives/solidity_types/datalake_compute/mod.rs index 36fd4ae6..bbefe0f2 100644 --- a/hdp/src/primitives/solidity_types/datalake_compute/mod.rs +++ b/hdp/src/primitives/solidity_types/datalake_compute/mod.rs @@ -106,6 +106,8 @@ impl BatchedDatalakeComputeCodecs for BatchedDatalakeCompute { mod tests { use std::str::FromStr; + use alloy::primitives::b256; + use crate::primitives::{ aggregate_fn::FunctionContext, task::datalake::{ @@ -140,8 +142,7 @@ mod tests { assert_eq!( datalake_compute.commit(), - B256::from_str("0x931644ee9576d1a377d4c5ba642a9f96361663f31d867d36169623f782a887fc") - .unwrap() + b256!("931644ee9576d1a377d4c5ba642a9f96361663f31d867d36169623f782a887fc") ) } @@ -170,8 +171,7 @@ mod tests { assert_eq!( datalake_compute.commit(), - B256::from_str("0xa15da24b3eb2bb5260f59a71c3934b64e2747d8e934563ad532e7f877a061bed") - .unwrap() + b256!("a15da24b3eb2bb5260f59a71c3934b64e2747d8e934563ad532e7f877a061bed") ) } } diff --git a/hdp/src/primitives/solidity_types/module.rs b/hdp/src/primitives/solidity_types/module.rs index c6678742..0916e8d0 100644 --- a/hdp/src/primitives/solidity_types/module.rs +++ b/hdp/src/primitives/solidity_types/module.rs @@ -34,8 +34,7 @@ impl Module { #[cfg(test)] mod tests { - use std::str::FromStr; - + use alloy::primitives::b256; use starknet_crypto::Felt; use crate::primitives::task::module::{ModuleInput, Visibility}; @@ -63,8 +62,7 @@ mod tests { let expected_commit = module.commit(); assert_eq!( expected_commit, - B256::from_str("0x879869b6d237b92bfdd3f3f7b76baaa9ebb2a3ad5e8478d12cca258d3def05af") - .unwrap() + b256!("879869b6d237b92bfdd3f3f7b76baaa9ebb2a3ad5e8478d12cca258d3def05af") ); } @@ -89,8 +87,7 @@ mod tests { let expected_commit = module.commit(); assert_eq!( expected_commit, - B256::from_str("0xd81ebd27b719967e1df4edf64c9e3ce87635089e3462306af340a393625d8726") - .unwrap() + b256!("d81ebd27b719967e1df4edf64c9e3ce87635089e3462306af340a393625d8726") ); } } diff --git a/hdp/src/primitives/solidity_types/traits.rs b/hdp/src/primitives/solidity_types/traits.rs index 7aa92f93..176cece3 100644 --- a/hdp/src/primitives/solidity_types/traits.rs +++ b/hdp/src/primitives/solidity_types/traits.rs @@ -22,7 +22,7 @@ pub trait Codecs { Self: Sized; } -/// Codecs for [`DatalakeCompute`] +/// Codecs for datalake task pub trait DatalakeComputeCodecs { fn decode(encoded_datalake: &[u8], encoded_compute: &[u8]) -> Result where @@ -31,7 +31,7 @@ pub trait DatalakeComputeCodecs { fn commit(&self) -> B256; } -/// Codecs for [`BatchedDatalakeCompute`] +/// Codecs for vector of datalake task pub trait BatchedDatalakeComputeCodecs { fn decode(encoded_datalake: &[u8], encoded_compute: &[u8]) -> Result where diff --git a/hdp/src/primitives/task/datalake/block_sampled/collection.rs b/hdp/src/primitives/task/datalake/block_sampled/collection.rs index c342eb68..fe3da9e2 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/collection.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/collection.rs @@ -8,7 +8,7 @@ use crate::primitives::task::datalake::{DatalakeCollection, DatalakeField}; use super::rlp_fields::{AccountField, HeaderField}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum BlockSampledCollection { Header(HeaderField), diff --git a/hdp/src/primitives/task/datalake/block_sampled/datalake.rs b/hdp/src/primitives/task/datalake/block_sampled/datalake.rs index 7242e98c..850d249c 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/datalake.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/datalake.rs @@ -5,12 +5,13 @@ use crate::primitives::{task::datalake::envelope::default_increment, ChainId}; use super::collection::BlockSampledCollection; /// [`BlockSampledDatalake`] is a struct that represents a block sampled datalake. -/// It contains the block range, the sampled property, and the increment. +/// It contains chain id, block range, the sampled property, and the increment. /// -/// The block range is inclusive, so the block range is from `block_range_start` to `block_range_end` +/// Inclusive block range: [block_range_start..block_range_end] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockSampledDatalake { + /// Chain id of the datalake pub chain_id: ChainId, /// The start of the block range pub block_range_start: u64, diff --git a/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs b/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs index 138f6333..36936f86 100644 --- a/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs +++ b/hdp/src/primitives/task/datalake/block_sampled/rlp_fields.rs @@ -13,7 +13,7 @@ use crate::{ primitives::task::datalake::DatalakeField, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum HeaderField { ParentHash, @@ -138,9 +138,7 @@ impl DatalakeField for HeaderField { match self { HeaderField::ParentHash => decoded.parent_hash.into(), HeaderField::OmmerHash => decoded.ommers_hash.into(), - HeaderField::Beneficiary => { - U256::from_str_radix(&decoded.beneficiary.to_string(), 16).unwrap() - } + HeaderField::Beneficiary => decoded.beneficiary.into_word().into(), HeaderField::StateRoot => decoded.state_root.into(), HeaderField::TransactionsRoot => decoded.transactions_root.into(), HeaderField::ReceiptsRoot => decoded.receipts_root.into(), @@ -240,7 +238,7 @@ impl Display for HeaderField { // == Account Field == -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum AccountField { Nonce, diff --git a/hdp/src/primitives/task/datalake/datalake_type.rs b/hdp/src/primitives/task/datalake/datalake_type.rs index aa16dfd4..1cd1177e 100644 --- a/hdp/src/primitives/task/datalake/datalake_type.rs +++ b/hdp/src/primitives/task/datalake/datalake_type.rs @@ -2,10 +2,10 @@ use anyhow::{bail, Result}; use serde::{Deserialize, Serialize}; use std::str::FromStr; -/// Identifier for a [`BlockSampledDatalake`] type. +/// Identifier for a BlockSampledDatalake pub const BLOCK_SAMPLED_DATALAKE_TYPE_ID: u8 = 0; -/// Identifier for an [`TransactionsDatalake`] type. +/// Identifier for a TransactionsDatalake pub const TRANSACTIONS_IN_BLOCK_DATALAKE_TYPE_ID: u8 = 1; #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)] diff --git a/hdp/src/primitives/task/datalake/envelope.rs b/hdp/src/primitives/task/datalake/envelope.rs index e592162f..00dfe2de 100644 --- a/hdp/src/primitives/task/datalake/envelope.rs +++ b/hdp/src/primitives/task/datalake/envelope.rs @@ -18,10 +18,8 @@ pub enum DatalakeEnvelope { impl DatalakeEnvelope { pub fn get_collection_type(&self) -> Box { match self { - DatalakeEnvelope::BlockSampled(datalake) => Box::new(datalake.sampled_property.clone()), - DatalakeEnvelope::TransactionsInBlock(datalake) => { - Box::new(datalake.sampled_property.clone()) - } + DatalakeEnvelope::BlockSampled(datalake) => Box::new(datalake.sampled_property), + DatalakeEnvelope::TransactionsInBlock(datalake) => Box::new(datalake.sampled_property), } } diff --git a/hdp/src/primitives/task/datalake/transactions/collection.rs b/hdp/src/primitives/task/datalake/transactions/collection.rs index a31444bd..5e3310c8 100644 --- a/hdp/src/primitives/task/datalake/transactions/collection.rs +++ b/hdp/src/primitives/task/datalake/transactions/collection.rs @@ -37,7 +37,7 @@ impl FromStr for TransactionsCollectionType { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(try_from = "String")] pub enum TransactionsCollection { Transactions(TransactionField), diff --git a/hdp/src/primitives/task/datalake/transactions/datalake.rs b/hdp/src/primitives/task/datalake/transactions/datalake.rs index dee89bd6..b64074df 100644 --- a/hdp/src/primitives/task/datalake/transactions/datalake.rs +++ b/hdp/src/primitives/task/datalake/transactions/datalake.rs @@ -5,6 +5,7 @@ //! Example: `TransactionsInBlockDatalake { target_block: 100, sampled_property: "tx.to", increment: 1 }` //! represents all transactions in block 100 with a `tx.to` property sampled with an increment of 1. +use core::fmt::Display; use std::num::ParseIntError; use std::str::FromStr; @@ -17,22 +18,27 @@ use crate::primitives::{task::datalake::envelope::default_increment, ChainId}; use super::TransactionsCollection; +/// [`TransactionsInBlockDatalake`] is a struct that represents a transactions datalake. +/// It contains chain id, target block, transaction range, sampled property, and other properties. +/// +/// Transaction range: [start_index..end_index] with specified increment #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TransactionsInBlockDatalake { + /// Chain id of the datalake pub chain_id: ChainId, - // target block number + /// Target block number pub target_block: u64, - // start index of transactions range ( default 0 ) + /// Start index of transactions range (default 0) pub start_index: u64, - // end index of transactions range, not included in the range ( default last ) + /// End index of transactions range, not included in the range (default last) pub end_index: u64, - // increment of transactions, Defaults to 1 if not present. + /// Increment of transactions, Defaults to 1 if not present. #[serde(default = "default_increment")] pub increment: u64, - // filter out the specific type of Txs + /// Filter out the specific type of Txs pub included_types: IncludedTypes, - // ex. "tx.to" , "tx.gas_price" or "tx_receipt.success", "tx_receipt.cumulative_gas_used" + /// Sampled property (e.g., "tx.to", "tx.gas_price", "tx_receipt.success", "tx_receipt.cumulative_gas_used") pub sampled_property: TransactionsCollection, } @@ -66,7 +72,7 @@ impl TransactionsInBlockDatalake { /// 1: EIP-2930 /// 2: EIP-1559 /// 3: EIP-4844 -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub struct IncludedTypes { legacy: bool, eip2930: bool, @@ -75,6 +81,14 @@ pub struct IncludedTypes { } impl IncludedTypes { + /// All transaction types(Legacy, EIP-1559, EIP-2930, EIP-4844) are included + pub const ALL: Self = Self { + legacy: true, + eip1559: true, + eip2930: true, + eip4844: true, + }; + pub fn to_be_bytes(&self) -> [u8; 4] { let mut bytes = [0; 4]; if self.legacy { @@ -114,7 +128,15 @@ impl IncludedTypes { included_types } - pub fn from(included_types: &[u8]) -> Self { + /// Converts a slice of bytes into an [`IncludedTypes`] instance. + /// + /// # Panics + /// + /// This function will panic if: + /// - The input slice is not exactly 4 bytes long. + /// - Any byte in the slice is not 0 or 1. + /// - All bytes in the slice are 0 (i.e., no transaction type is included). + pub fn from_bytes(included_types: &[u8]) -> Self { if included_types.len() != 4 { panic!("Included types must be 4 bytes long"); } @@ -134,19 +156,31 @@ impl IncludedTypes { let inner_bytes = self.to_be_bytes(); inner_bytes[target_type as usize] != 0 } +} + +impl Display for IncludedTypes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let bytes = self.to_be_bytes(); + write!(f, "{},{},{},{}", bytes[0], bytes[1], bytes[2], bytes[3]) + } +} - pub fn to_uint256(&self) -> U256 { +impl From for U256 { + fn from(value: IncludedTypes) -> U256 { let mut bytes = [0; 32]; - let inner_bytes = self.to_be_bytes(); + let inner_bytes = value.to_be_bytes(); bytes[28..32].copy_from_slice(&inner_bytes); U256::from_be_bytes(bytes) } +} - pub fn from_uint256(value: U256) -> Self { +// Implementation of From for Self +impl From for IncludedTypes { + fn from(value: U256) -> IncludedTypes { let bytes: [u8; 32] = value.to_be_bytes(); let mut inner = [0; 4]; inner.copy_from_slice(&bytes[28..32]); - Self::from_be_bytes(inner) + IncludedTypes::from_be_bytes(inner) } } @@ -163,7 +197,7 @@ impl FromStr for IncludedTypes { panic!("Included types must be 4 bytes long"); } - Ok(IncludedTypes::from(&included_types)) + Ok(IncludedTypes::from_bytes(&included_types)) } } @@ -173,16 +207,16 @@ mod tests { #[test] fn test_included_types() { - let included_types = IncludedTypes::from(&[1, 1, 1, 1]); + let included_types = IncludedTypes::ALL; assert!(included_types.is_included(TxType::Legacy)); assert!(included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); assert!(included_types.is_included(TxType::Eip4844)); - let uint256 = included_types.to_uint256(); + let uint256: U256 = included_types.into(); assert_eq!(uint256, U256::from(0x01010101)); - let included_types = IncludedTypes::from_uint256(uint256); + let included_types = IncludedTypes::from(uint256); assert!(included_types.is_included(TxType::Legacy)); assert!(included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); @@ -191,19 +225,32 @@ mod tests { #[test] fn test_included_types_partial() { - let included_types = IncludedTypes::from(&[1, 0, 1, 0]); + let included_types = IncludedTypes::from_bytes(&[1, 0, 1, 0]); assert!(included_types.is_included(TxType::Legacy)); assert!(!included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); assert!(!included_types.is_included(TxType::Eip4844)); - let uint256 = included_types.to_uint256(); + let uint256: U256 = included_types.into(); assert_eq!(uint256, U256::from(0x01000100)); - let included_types = IncludedTypes::from_uint256(uint256); + let included_types = IncludedTypes::from(uint256); assert!(included_types.is_included(TxType::Legacy)); assert!(!included_types.is_included(TxType::Eip2930)); assert!(included_types.is_included(TxType::Eip1559)); assert!(!included_types.is_included(TxType::Eip4844)); } + + #[test] + fn test_included_types_from_str_to_str() { + let input_str = "1,0,1,0"; + let included_types = IncludedTypes::from_str(input_str).unwrap(); + assert!(included_types.is_included(TxType::Legacy)); + assert!(!included_types.is_included(TxType::Eip2930)); + assert!(included_types.is_included(TxType::Eip1559)); + assert!(!included_types.is_included(TxType::Eip4844)); + + let output_str = included_types.to_string(); + assert_eq!(input_str, output_str); + } } diff --git a/hdp/src/primitives/task/datalake/transactions/mod.rs b/hdp/src/primitives/task/datalake/transactions/mod.rs index 3abcef5b..9fb5a93e 100644 --- a/hdp/src/primitives/task/datalake/transactions/mod.rs +++ b/hdp/src/primitives/task/datalake/transactions/mod.rs @@ -9,15 +9,12 @@ pub use rlp_fields::*; #[cfg(test)] mod tests { - - use std::str::FromStr; - use crate::primitives::{ solidity_types::traits::DatalakeCodecs, task::datalake::DatalakeCollection, ChainId, }; use alloy::{ hex, - primitives::{B256, U256}, + primitives::{b256, U256}, }; use super::*; @@ -33,7 +30,7 @@ mod tests { 1, 10, 2, - IncludedTypes::from(&[1, 1, 1, 1]), + IncludedTypes::ALL, ); let encoded = transaction_datalake.encode().unwrap(); @@ -42,8 +39,7 @@ mod tests { assert_eq!( transaction_datalake.commit(), - B256::from_str("0x0a1ad7357827238fdbea5c8f34df65e7313c18388026fad78a75d4b5a6be71b7") - .unwrap() + b256!("0a1ad7357827238fdbea5c8f34df65e7313c18388026fad78a75d4b5a6be71b7") ); assert_eq!( @@ -51,10 +47,8 @@ mod tests { TransactionsCollection::Transactions(TransactionField::Nonce) ); - assert_eq!( - transaction_datalake.included_types.to_uint256(), - U256::from(0x01010101) - ); + let converted: U256 = transaction_datalake.included_types.into(); + assert_eq!(converted, U256::from(0x01010101)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); assert_eq!(decoded, transaction_datalake); @@ -72,7 +66,7 @@ mod tests { 1, 10, 2, - IncludedTypes::from(&[1, 0, 0, 1]), + IncludedTypes::from_bytes(&[1, 0, 0, 1]), ); let encoded = transaction_datalake.encode().unwrap(); @@ -81,8 +75,7 @@ mod tests { assert_eq!( transaction_datalake.commit(), - B256::from_str("0x991d3d38a26f54aed67f8391bab26c855dedd2fd810931542625b6ad4f7c1e42") - .unwrap() + b256!("991d3d38a26f54aed67f8391bab26c855dedd2fd810931542625b6ad4f7c1e42") ); assert_eq!( @@ -90,10 +83,8 @@ mod tests { TransactionsCollection::TranasactionReceipts(TransactionReceiptField::Success) ); - assert_eq!( - transaction_datalake.included_types.to_uint256(), - U256::from(0x01000001) - ); + let converted: U256 = transaction_datalake.included_types.into(); + assert_eq!(converted, U256::from(0x01000001)); let decoded = TransactionsInBlockDatalake::decode(&encoded).unwrap(); assert_eq!(decoded, transaction_datalake); diff --git a/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs b/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs index 3fa1c943..bdb497c0 100644 --- a/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs +++ b/hdp/src/primitives/task/datalake/transactions/rlp_fields.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::primitives::task::datalake::DatalakeField; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum TransactionField { // ===== Transaction fields ===== Nonce, @@ -207,7 +207,7 @@ impl Display for TransactionField { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum TransactionReceiptField { Success, CumulativeGasUsed, diff --git a/hdp/src/primitives/task/module.rs b/hdp/src/primitives/task/module.rs index c31a8b62..1e96b9ef 100644 --- a/hdp/src/primitives/task/module.rs +++ b/hdp/src/primitives/task/module.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use starknet::core::serde::unsigned_field_element::UfeHex; -use starknet_crypto::Felt; +use starknet_types_core::felt::Felt; use std::{path::PathBuf, str::FromStr}; #[serde_as] @@ -31,7 +31,7 @@ impl ModuleInput { pub fn new(visibility: Visibility, value: &str) -> Self { Self { visibility, - value: Felt::from_hex(value).unwrap(), + value: Felt::from_hex(value).expect("invalid hex string value to convert Felt"), } } } @@ -62,6 +62,13 @@ impl FromStr for ModuleInput { } } +impl From for ModuleInput { + fn from(s: String) -> Self { + s.parse() + .unwrap_or_else(|_| ModuleInput::new(Visibility::Private, &s)) + } +} + impl Module { pub fn new( program_hash: Felt, diff --git a/hdp/src/primitives/utils.rs b/hdp/src/primitives/utils.rs index 9645bc38..503c0138 100644 --- a/hdp/src/primitives/utils.rs +++ b/hdp/src/primitives/utils.rs @@ -46,7 +46,7 @@ pub fn tx_index_to_tx_key(tx_index: u64) -> String { format!("0x{}", hex::encode(binding)) } -/// Convert a `FieldElement` into a `FixedBytes<32>` +/// Convert a [`Felt`] into a [`FixedBytes<32>`] pub fn felt_to_bytes32(felt: Felt) -> FixedBytes<32> { let felt_bytes = felt.to_bytes_be(); B256::from(felt_bytes) diff --git a/hdp/src/provider/error.rs b/hdp/src/provider/error.rs index c82699fb..d35f84d6 100644 --- a/hdp/src/provider/error.rs +++ b/hdp/src/provider/error.rs @@ -1,9 +1,8 @@ +use alloy::primitives::BlockNumber; use thiserror::Error; use crate::provider::indexer::IndexerError; -use super::evm::rpc::RpcProviderError; - /// Error type for provider #[derive(Error, Debug)] pub enum ProviderError { @@ -19,11 +18,11 @@ pub enum ProviderError { #[error("MMR not found")] MmrNotFound, - /// Error from the [`Indexer`] + /// Error from the [`IndexerError`] #[error("Failed from indexer")] IndexerError(#[from] IndexerError), - /// Error from [`RpcProvider`] + /// Error from [`RpcProviderError`] #[error("Failed to get proofs: {0}")] EvmRpcProviderError(#[from] RpcProviderError), @@ -34,3 +33,22 @@ pub enum ProviderError { #[error("Fetch key error: {0}")] FetchKeyError(String), } + +/// Error from rpc +#[derive(Error, Debug)] +pub enum RpcProviderError { + #[error("Failed to send proofs with mpsc")] + MpscError( + #[from] + tokio::sync::mpsc::error::SendError<( + BlockNumber, + alloy::rpc::types::EIP1186AccountProofResponse, + )>, + ), + + #[error("Failed to fetch proofs: {0}")] + ReqwestError(#[from] reqwest::Error), + + #[error("Failed to parse response: {0}")] + SerdeJsonError(#[from] serde_json::Error), +} diff --git a/hdp/src/provider/evm/datalake/block_sampled.rs b/hdp/src/provider/evm/datalake/block_sampled.rs index 84db7c6f..f3ffee92 100644 --- a/hdp/src/provider/evm/datalake/block_sampled.rs +++ b/hdp/src/provider/evm/datalake/block_sampled.rs @@ -2,7 +2,8 @@ use crate::{ primitives::{ block::account::Account, processed_types::{ - account::ProcessedAccount, header::ProcessedHeader, mpt::ProcessedMPTProof, + account::ProcessedAccount, block_proofs::convert_to_mmr_with_headers, + header::ProcessedHeader, mmr::MMRMeta, mpt::ProcessedMPTProof, storage::ProcessedStorage, }, task::datalake::{ @@ -12,7 +13,7 @@ use crate::{ }, provider::{error::ProviderError, evm::provider::EvmProvider, types::FetchedDatalake}, }; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use alloy::primitives::{Bytes, U256}; use anyhow::Result; @@ -24,14 +25,15 @@ impl EvmProvider { ) -> Result { let mut aggregation_set: Vec = Vec::new(); - let (mmr_metas, headers_proofs) = self + let headers_proofs = self .get_range_of_header_proofs( datalake.block_range_start, datalake.block_range_end, datalake.increment, ) .await?; - let mut headers: HashSet = HashSet::new(); + let mut mmr_with_headers: HashMap> = HashMap::new(); + let mut accounts: HashSet = HashSet::new(); let mut storages: HashSet = HashSet::new(); let block_range = (datalake.block_range_start..=datalake.block_range_end) @@ -40,16 +42,26 @@ impl EvmProvider { match &datalake.sampled_property { BlockSampledCollection::Header(property) => { for block in block_range { - let fetched_block = headers_proofs.get(&block).unwrap(); + let (fetched_block, mmr) = headers_proofs.get(&block).unwrap(); let value = property.decode_field_from_rlp(&Bytes::from( fetched_block.rlp_block_header.clone(), )); - headers.insert(ProcessedHeader::new( + let processed_header = ProcessedHeader::new( fetched_block.rlp_block_header.clone(), fetched_block.element_index, fetched_block.siblings_hashes.clone(), - )); + ); aggregation_set.push(value); + mmr_with_headers + .entry(mmr.clone()) + .and_modify(|existing_headers| { + existing_headers.insert(processed_header.clone()); + }) + .or_insert_with(|| { + let mut new_set = HashSet::new(); + new_set.insert(processed_header); + new_set + }); } } BlockSampledCollection::Account(address, property) => { @@ -65,16 +77,16 @@ impl EvmProvider { let mut account_proofs: Vec = vec![]; for block in block_range { - let fetched_block = headers_proofs.get(&block).unwrap().clone(); + let (fetched_block, mmr) = headers_proofs.get(&block).unwrap().clone(); let account_proof = accounts_and_proofs_result.get(&block).unwrap().clone(); let account = Account::from(&account_proof).rlp_encode(); let value = property.decode_field_from_rlp(&account); - headers.insert(ProcessedHeader::new( + let processed_header = ProcessedHeader::new( fetched_block.rlp_block_header.clone(), fetched_block.element_index, fetched_block.siblings_hashes.clone(), - )); + ); let account_proof = ProcessedMPTProof { block_number: block, @@ -83,6 +95,16 @@ impl EvmProvider { account_proofs.push(account_proof); aggregation_set.push(value); + mmr_with_headers + .entry(mmr.clone()) + .and_modify(|existing_headers| { + existing_headers.insert(processed_header.clone()); + }) + .or_insert_with(|| { + let mut new_set = HashSet::new(); + new_set.insert(processed_header); + new_set + }); } accounts.insert(ProcessedAccount::new(*address, account_proofs)); @@ -102,14 +124,14 @@ impl EvmProvider { let mut account_proofs: Vec = vec![]; for i in block_range { - let fetched_block = headers_proofs.get(&i).unwrap().clone(); + let (fetched_block, mmr) = headers_proofs.get(&i).unwrap().clone(); let storage_proof = storages_and_proofs_result.get(&i).unwrap().clone(); - headers.insert(ProcessedHeader::new( + let processed_header = ProcessedHeader::new( fetched_block.rlp_block_header.clone(), fetched_block.element_index, fetched_block.siblings_hashes.clone(), - )); + ); account_proofs.push(ProcessedMPTProof::new(i, storage_proof.account_proof)); @@ -119,6 +141,16 @@ impl EvmProvider { )); aggregation_set.push(storage_proof.storage_proof[0].value); + mmr_with_headers + .entry(mmr.clone()) + .and_modify(|existing_headers| { + existing_headers.insert(processed_header.clone()); + }) + .or_insert_with(|| { + let mut new_set = HashSet::new(); + new_set.insert(processed_header); + new_set + }); } storages.insert(ProcessedStorage::new(*address, *slot, storage_proofs)); @@ -128,12 +160,11 @@ impl EvmProvider { Ok(FetchedDatalake { values: aggregation_set, - headers, + mmr_with_headers: HashSet::from_iter(convert_to_mmr_with_headers(mmr_with_headers)), accounts, storages, transactions: HashSet::new(), transaction_receipts: HashSet::new(), - mmr_metas, }) } } diff --git a/hdp/src/provider/evm/datalake/transactions.rs b/hdp/src/provider/evm/datalake/transactions.rs index 38002edf..e8eb6340 100644 --- a/hdp/src/provider/evm/datalake/transactions.rs +++ b/hdp/src/provider/evm/datalake/transactions.rs @@ -1,7 +1,8 @@ use crate::{ primitives::{ processed_types::{ - header::ProcessedHeader, receipt::ProcessedReceipt, transaction::ProcessedTransaction, + block_proofs::convert_to_mmr_with_headers, header::ProcessedHeader, mmr::MMRMeta, + receipt::ProcessedReceipt, transaction::ProcessedTransaction, }, task::datalake::{ transactions::{TransactionsCollection, TransactionsInBlockDatalake}, @@ -13,7 +14,7 @@ use crate::{ use alloy::primitives::U256; use anyhow::Result; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; impl EvmProvider { pub async fn fetch_transactions( @@ -22,7 +23,7 @@ impl EvmProvider { ) -> Result { let mut aggregation_set: Vec = Vec::new(); - let (mmr_metas, headers_proofs) = self + let headers_proofs = self .get_range_of_header_proofs( datalake.target_block, datalake.target_block, @@ -30,16 +31,17 @@ impl EvmProvider { ) .await?; - let mut headers: HashSet = HashSet::new(); + let mut mmr_with_headers: HashMap> = HashMap::new(); let mut transactions: HashSet = HashSet::new(); let mut transaction_receipts: HashSet = HashSet::new(); - let fetched_block = headers_proofs.get(&datalake.target_block).unwrap(); + let (fetched_block, mmr) = headers_proofs.get(&datalake.target_block).unwrap(); - headers.insert(ProcessedHeader::new( + let processed_header = ProcessedHeader::new( fetched_block.rlp_block_header.clone(), fetched_block.element_index, fetched_block.siblings_hashes.clone(), - )); + ); + mmr_with_headers.insert(mmr.clone(), [processed_header].into_iter().collect()); match &datalake.sampled_property { TransactionsCollection::Transactions(property) => { @@ -92,12 +94,11 @@ impl EvmProvider { Ok(FetchedDatalake { values: aggregation_set, - headers, + mmr_with_headers: HashSet::from_iter(convert_to_mmr_with_headers(mmr_with_headers)), accounts: HashSet::new(), storages: HashSet::new(), transactions, transaction_receipts, - mmr_metas, }) } } diff --git a/hdp/src/provider/evm/from_keys.rs b/hdp/src/provider/evm/from_keys.rs index c216616e..b596e539 100644 --- a/hdp/src/provider/evm/from_keys.rs +++ b/hdp/src/provider/evm/from_keys.rs @@ -1,6 +1,8 @@ use super::provider::EvmProvider; use crate::primitives::processed_types::account::ProcessedAccount; -use crate::primitives::processed_types::block_proofs::ProcessedBlockProofs; +use crate::primitives::processed_types::block_proofs::{ + convert_to_mmr_with_headers, ProcessedBlockProofs, +}; use crate::primitives::processed_types::header::ProcessedHeader; use crate::primitives::processed_types::mmr::MMRMeta; use crate::primitives::processed_types::mpt::ProcessedMPTProof; @@ -9,8 +11,8 @@ use crate::primitives::processed_types::storage::ProcessedStorage; use crate::primitives::processed_types::transaction::ProcessedTransaction; use crate::provider::error::ProviderError; use crate::provider::key::{ - AccountMemorizerKey, CategorizedFetchKeys, HeaderMemorizerKey, StorageMemorizerKey, - TxMemorizerKey, TxReceiptMemorizerKey, + CategorizedFetchKeys, EvmAccountKey, EvmBlockReceiptKey, EvmBlockTxKey, EvmHeaderKey, + EvmStorageKey, }; use alloy::primitives::{Address, BlockNumber, Bytes, TxIndex, B256}; use alloy::transports::{RpcError, TransportErrorKind}; @@ -27,8 +29,9 @@ impl EvmProvider { &self, fetch_keys: CategorizedFetchKeys, ) -> Result { + let chain_id = self.header_provider.chain_id.to_numeric_id(); // fetch proofs using keys and construct result - let (headers, mmr_metas) = self.get_headers_from_keys(fetch_keys.headers).await?; + let mmr_with_headers = self.get_headers_from_keys(fetch_keys.headers).await?; let mut accounts = if fetch_keys.accounts.is_empty() { HashSet::new() } else { @@ -39,22 +42,22 @@ impl EvmProvider { } else { self.get_storages_from_keys(fetch_keys.storage).await? }; - let transactions = if fetch_keys.txs.is_empty() { + let transactions = if fetch_keys.block_txs.is_empty() { vec![] } else { - self.get_txs_from_keys(fetch_keys.txs).await? + self.get_txs_from_keys(fetch_keys.block_txs).await? }; - let transaction_receipts = if fetch_keys.tx_receipts.is_empty() { + let transaction_receipts = if fetch_keys.block_receipts.is_empty() { vec![] } else { - self.get_tx_receipts_from_keys(fetch_keys.tx_receipts) + self.get_tx_receipts_from_keys(fetch_keys.block_receipts) .await? }; accounts.extend(accounts_from_storage_key); let accounts_result: Vec = accounts.into_iter().collect(); Ok(ProcessedBlockProofs { - mmr_metas, - headers: headers.into_iter().collect(), + chain_id, + mmr_with_headers: convert_to_mmr_with_headers(mmr_with_headers), accounts: accounts_result, storages: storages.into_iter().collect(), transactions, @@ -64,8 +67,8 @@ impl EvmProvider { async fn get_headers_from_keys( &self, - keys: HashSet, - ) -> Result<(HashSet, Vec), ProviderError> { + keys: HashSet, + ) -> Result>, ProviderError> { let start_fetch = Instant::now(); let block_range = keys.iter().map(|x| x.block_number).collect::>(); @@ -80,9 +83,8 @@ impl EvmProvider { self._chunk_vec_blocks_for_indexer(block_range) }; - let chain_id = keys.iter().next().unwrap().chain_id; - let mut fetched_headers_proofs: HashSet = HashSet::new(); - let mut mmrs = HashSet::new(); + // let chain_id = keys.iter().next().unwrap().chain_id; + let mut fetched_headers_proofs: HashMap> = HashMap::new(); let real_target_blocks = keys.iter().map(|x| x.block_number).collect::>(); for target_blocks in target_blocks_batch { @@ -94,8 +96,8 @@ impl EvmProvider { .get_headers_proof(start_block, end_block) .await?; - // filter only the keys that are in the real target blocks - let keys_in_real_target_blocks = indexer_response + // filter only the keys that are in the real target blocks and create ProcessedHeaders + let keys_in_real_target_blocks: Vec = indexer_response .headers .into_iter() .filter(|(block_number, _)| real_target_blocks.contains(block_number)) @@ -105,20 +107,24 @@ impl EvmProvider { header_proof.element_index, header_proof.siblings_hashes, ) - }); + }) + .collect(); - fetched_headers_proofs.extend(keys_in_real_target_blocks); let fetched_mmr = indexer_response.mmr_meta; - let mmr_meta = MMRMeta::from_indexer(fetched_mmr, chain_id); - mmrs.insert(mmr_meta); + let mmr_meta = MMRMeta::from_indexer(fetched_mmr); + fetched_headers_proofs + .entry(mmr_meta) + .and_modify(|existing_headers| { + existing_headers.extend(keys_in_real_target_blocks.iter().cloned()); + }) + .or_insert_with(|| keys_in_real_target_blocks.into_iter().collect()); } let duration = start_fetch.elapsed(); info!("time taken (Headers Proofs Fetch): {:?}", duration); - if !mmrs.is_empty() { - let vec_mmrs = mmrs.into_iter().collect::>(); - Ok((fetched_headers_proofs, vec_mmrs)) + if !fetched_headers_proofs.is_empty() { + Ok(fetched_headers_proofs) } else { Err(ProviderError::MmrNotFound) } @@ -126,7 +132,7 @@ impl EvmProvider { async fn get_accounts_from_keys( &self, - keys: HashSet, + keys: HashSet, ) -> Result, ProviderError> { let mut fetched_accounts_proofs: HashSet = HashSet::new(); let start_fetch = Instant::now(); @@ -177,7 +183,7 @@ impl EvmProvider { async fn get_storages_from_keys( &self, - keys: HashSet, + keys: HashSet, ) -> Result<(HashSet, HashSet), ProviderError> { let mut fetched_accounts_proofs: HashSet = HashSet::new(); let mut fetched_storage_proofs: HashSet = HashSet::new(); @@ -243,7 +249,7 @@ impl EvmProvider { pub async fn get_txs_from_keys( &self, - keys: HashSet, + keys: HashSet, ) -> Result, ProviderError> { let mut fetched_transactions = vec![]; let start_fetch = Instant::now(); @@ -252,7 +258,7 @@ impl EvmProvider { let mut block_to_tx_range: HashMap> = HashMap::new(); for key in keys { let tx_range = block_to_tx_range.entry(key.block_number).or_default(); - tx_range.push(key.tx_index); + tx_range.push(key.index); } for (block_number, tx_range) in block_to_tx_range { @@ -292,7 +298,7 @@ impl EvmProvider { pub async fn get_tx_receipts_from_keys( &self, - keys: HashSet, + keys: HashSet, ) -> Result, ProviderError> { let mut fetched_transaction_receipts = vec![]; let start_fetch = Instant::now(); @@ -300,7 +306,7 @@ impl EvmProvider { let mut block_to_tx_range: HashMap> = HashMap::new(); for key in keys { let tx_range = block_to_tx_range.entry(key.block_number).or_default(); - tx_range.push(key.tx_index); + tx_range.push(key.index); } for (block_number, tx_range) in block_to_tx_range { @@ -350,8 +356,8 @@ mod tests { use super::*; use crate::provider::evm::provider::EvmProvider; use crate::provider::key::categorize_fetch_keys; - use crate::provider::key::FetchKeyEnvelope; - use crate::provider::key::{AccountMemorizerKey, HeaderMemorizerKey}; + use crate::provider::key::EvmFetchKeyEnvelope; + use crate::provider::key::{EvmAccountKey, EvmHeaderKey}; use alloy::primitives::address; use dotenv::dotenv; use std::sync::Once; @@ -371,14 +377,14 @@ mod tests { let target_chain_id = crate::primitives::ChainId::EthereumSepolia; let provider = EvmProvider::default(); let keys = vec![ - FetchKeyEnvelope::Header(HeaderMemorizerKey::new(target_chain_id, 1)), - FetchKeyEnvelope::Header(HeaderMemorizerKey::new(target_chain_id, 2)), - FetchKeyEnvelope::Header(HeaderMemorizerKey::new(target_chain_id, 3)), + EvmFetchKeyEnvelope::Header(EvmHeaderKey::new(target_chain_id, 1)), + EvmFetchKeyEnvelope::Header(EvmHeaderKey::new(target_chain_id, 2)), + EvmFetchKeyEnvelope::Header(EvmHeaderKey::new(target_chain_id, 3)), ]; let (chain_id, fetched_keys) = categorize_fetch_keys(keys).into_iter().next().unwrap(); assert_eq!(chain_id, target_chain_id); let proofs = provider.fetch_proofs_from_keys(fetched_keys).await.unwrap(); - assert_eq!(proofs.headers.len(), 3); + assert_eq!(proofs.mmr_with_headers[0].headers.len(), 3); } #[tokio::test] @@ -389,13 +395,13 @@ mod tests { let provider = EvmProvider::default(); let target_address = address!("7f2c6f930306d3aa736b3a6c6a98f512f74036d4"); let keys = vec![ - FetchKeyEnvelope::Account(AccountMemorizerKey::new( + EvmFetchKeyEnvelope::Account(EvmAccountKey::new( target_chain_id, 6127485, target_address, )), - FetchKeyEnvelope::Account(AccountMemorizerKey::new(target_chain_id, 0, target_address)), - FetchKeyEnvelope::Account(AccountMemorizerKey::new( + EvmFetchKeyEnvelope::Account(EvmAccountKey::new(target_chain_id, 0, target_address)), + EvmFetchKeyEnvelope::Account(EvmAccountKey::new( target_chain_id, 6127487, target_address, @@ -405,7 +411,7 @@ mod tests { assert_eq!(chain_id, target_chain_id); let proofs = provider.fetch_proofs_from_keys(fetched_keys).await.unwrap(); assert_eq!(proofs.accounts[0].proofs.len(), 3); - assert_eq!(proofs.headers.len(), 3); + assert_eq!(proofs.mmr_with_headers[0].headers.len(), 3); } #[tokio::test] @@ -418,37 +424,37 @@ mod tests { let target_address = address!("7f2c6f930306d3aa736b3a6c6a98f512f74036d4"); let target_slot = B256::ZERO; let keys = vec![ - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 0, target_address, target_slot, )), - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 6127486, target_address, target_slot, )), - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 6127487, target_address, target_slot, )), - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 4127497, target_address, target_slot, )), - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 4127487, target_address, target_slot, )), - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( target_chain_id, 4127477, target_address, @@ -460,7 +466,7 @@ mod tests { let proofs = provider.fetch_proofs_from_keys(fetched_keys).await.unwrap(); let duration = start_fetch.elapsed(); println!("Time taken (Total Proofs Fetch): {:?}", duration); - assert_eq!(proofs.headers.len(), 6); + assert_eq!(proofs.mmr_with_headers[0].headers.len(), 6); assert_eq!(proofs.accounts[0].proofs.len(), 6); assert_eq!(proofs.storages[0].proofs.len(), 6); } @@ -472,14 +478,14 @@ mod tests { let target_chain_id = crate::primitives::ChainId::EthereumSepolia; let provider = EvmProvider::default(); let keys = vec![ - FetchKeyEnvelope::Tx(TxMemorizerKey::new(target_chain_id, 1000, 0)), - FetchKeyEnvelope::Tx(TxMemorizerKey::new(target_chain_id, 1001, 1)), - FetchKeyEnvelope::Tx(TxMemorizerKey::new(target_chain_id, 1000, 2)), + EvmFetchKeyEnvelope::Tx(EvmBlockTxKey::new(target_chain_id, 1000, 0)), + EvmFetchKeyEnvelope::Tx(EvmBlockTxKey::new(target_chain_id, 1001, 1)), + EvmFetchKeyEnvelope::Tx(EvmBlockTxKey::new(target_chain_id, 1000, 2)), ]; let (chain_id, fetched_keys) = categorize_fetch_keys(keys).into_iter().next().unwrap(); assert_eq!(chain_id, target_chain_id); let proofs = provider.fetch_proofs_from_keys(fetched_keys).await.unwrap(); - assert_eq!(proofs.headers.len(), 2); + assert_eq!(proofs.mmr_with_headers[0].headers.len(), 2); assert_eq!(proofs.transactions.len(), 3); } } diff --git a/hdp/src/provider/evm/provider.rs b/hdp/src/provider/evm/provider.rs index 58c43156..defcfcea 100644 --- a/hdp/src/provider/evm/provider.rs +++ b/hdp/src/provider/evm/provider.rs @@ -19,10 +19,7 @@ use eth_trie_proofs::{ }; use itertools::Itertools; use reqwest::Url; -use std::{ - collections::{HashMap, HashSet}, - time::Instant, -}; +use std::{collections::HashMap, time::Instant}; use tracing::info; use crate::{ @@ -32,13 +29,8 @@ use crate::{ use super::rpc::RpcProvider; -type HeaderProofsResult = Result< - ( - HashSet, - HashMap, - ), - ProviderError, ->; +type HeaderProofsResult = + Result, ProviderError>; type AccountProofsResult = Result, ProviderError>; type StorageProofsResult = Result, ProviderError>; type TxProofsResult = Result, ProviderError>; @@ -97,8 +89,10 @@ impl EvmProvider { let target_blocks_batch: Vec> = self._chunk_block_range(from_block, to_block, increment); - let mut fetched_headers_proofs_with_blocks_map = HashMap::new(); - let mut mmrs = HashSet::new(); + let mut fetched_headers_proofs_with_blocks_map: HashMap< + u64, + (MMRProofFromNewIndexer, MMRMeta), + > = HashMap::new(); for target_blocks in target_blocks_batch { let (start_block, end_block) = @@ -108,20 +102,24 @@ impl EvmProvider { .header_provider .get_headers_proof(start_block, end_block) .await?; - - fetched_headers_proofs_with_blocks_map.extend(indexer_response.headers); let fetched_mmr = indexer_response.mmr_meta; - let mmr_meta = MMRMeta::from_indexer(fetched_mmr, self.header_provider.chain_id); - mmrs.insert(mmr_meta); + let mmr_meta = MMRMeta::from_indexer(fetched_mmr); + + // TODO lets think how not clone the mmr_meta + fetched_headers_proofs_with_blocks_map.extend( + indexer_response + .headers + .into_iter() + .map(|(block_number, header_proof)| { + (block_number, (header_proof, mmr_meta.clone())) + }), + ); } let duration = start_fetch.elapsed(); info!("time taken (Headers Proofs Fetch): {:?}", duration); - if !mmrs.is_empty() { - Ok((mmrs, fetched_headers_proofs_with_blocks_map)) - } else { - Err(ProviderError::MmrNotFound) - } + + Ok(fetched_headers_proofs_with_blocks_map) } /// Fetches the account proofs for the given block range. @@ -475,10 +473,11 @@ mod tests { initialize(); let start_time = Instant::now(); let provider = EvmProvider::default(); - let (_meta, header_response) = provider + let header_response = provider .get_range_of_header_proofs(6127485, 6127485 + 2000 - 1, 1) .await?; assert_eq!(header_response.len(), 2000); + // assert_eq!(meta.mmr_id, 26); let duration = start_time.elapsed(); println!("Time taken (Header Fetch): {:?}", duration); diff --git a/hdp/src/provider/evm/rpc.rs b/hdp/src/provider/evm/rpc.rs index 37ffd6ae..7ce023ad 100644 --- a/hdp/src/provider/evm/rpc.rs +++ b/hdp/src/provider/evm/rpc.rs @@ -15,25 +15,13 @@ use alloy::{ }; use futures::future::join_all; use reqwest::Url; -use thiserror::Error; use tokio::sync::{ mpsc::{self, Sender}, RwLock, }; use tracing::debug; -/// Error from [`RpcProvider`] -#[derive(Error, Debug)] -pub enum RpcProviderError { - #[error("Failed to send proofs with mpsc")] - MpscError( - #[from] - tokio::sync::mpsc::error::SendError<( - BlockNumber, - alloy::rpc::types::EIP1186AccountProofResponse, - )>, - ), -} +use crate::provider::error::RpcProviderError; /// RPC provider for fetching data from Ethereum RPC /// It is a wrapper around the alloy provider, using eth_getProof for fetching account and storage proofs diff --git a/hdp/src/provider/indexer.rs b/hdp/src/provider/indexer.rs index 1929fb57..09519a68 100644 --- a/hdp/src/provider/indexer.rs +++ b/hdp/src/provider/indexer.rs @@ -53,13 +53,14 @@ impl ChainId { /// Indexer client for fetching MMR and headers proof from Herodotus Indexer /// -/// For more information, see: https://rs-indexer.api.herodotus.cloud/swagger +/// For more information, see: /// /// How to use: /// ```rust /// use hdp::provider::indexer::{Indexer, IndexerError}; +/// use hdp::primitives::ChainId; /// -/// async fn call_indexer(chain_id: u64, block_range_start: u64, block_range_end: u64) -> Result<(), IndexerError> { +/// async fn call_indexer(chain_id: ChainId, block_range_start: u64, block_range_end: u64) -> Result<(), IndexerError> { /// let indexer = Indexer::new(chain_id); /// let response = indexer.get_headers_proof(block_range_start, block_range_end).await?; /// Ok(()) diff --git a/hdp/src/provider/key.rs b/hdp/src/provider/key.rs index 6c56ffcd..d49baa30 100644 --- a/hdp/src/provider/key.rs +++ b/hdp/src/provider/key.rs @@ -21,27 +21,27 @@ use serde::{Deserialize, Serialize}; /// This is keys that are categorized into different subsets of keys. #[derive(Debug, Default)] pub struct CategorizedFetchKeys { - pub headers: HashSet, - pub accounts: HashSet, - pub storage: HashSet, - pub txs: HashSet, - pub tx_receipts: HashSet, + pub headers: HashSet, + pub accounts: HashSet, + pub storage: HashSet, + pub block_txs: HashSet, + pub block_receipts: HashSet, } impl CategorizedFetchKeys { pub fn new( - headers: HashSet, - accounts: HashSet, - storage: HashSet, - txs: HashSet, - tx_receipts: HashSet, + headers: HashSet, + accounts: HashSet, + storage: HashSet, + block_txs: HashSet, + block_receipts: HashSet, ) -> Self { Self { headers, accounts, storage, - txs, - tx_receipts, + block_txs, + block_receipts, } } } @@ -49,7 +49,7 @@ impl CategorizedFetchKeys { /// Categorize fetch keys /// This is require to initiate multiple provider for different chain and fetch keys types pub fn categorize_fetch_keys( - fetch_keys: Vec, + fetch_keys: Vec, ) -> Vec<(ChainId, CategorizedFetchKeys)> { let mut chain_id_map: HashMap = std::collections::HashMap::new(); @@ -58,45 +58,42 @@ pub fn categorize_fetch_keys( let target_categorized_fetch_keys = chain_id_map.entry(chain_id).or_default(); match key { - FetchKeyEnvelope::Header(header_key) => { + EvmFetchKeyEnvelope::Header(header_key) => { target_categorized_fetch_keys.headers.insert(header_key); } - FetchKeyEnvelope::Account(account_key) => { + EvmFetchKeyEnvelope::Account(account_key) => { target_categorized_fetch_keys .headers - .insert(HeaderMemorizerKey::new( + .insert(EvmHeaderKey::new( account_key.chain_id, account_key.block_number, )); target_categorized_fetch_keys.accounts.insert(account_key); } - FetchKeyEnvelope::Storage(storage_key) => { + EvmFetchKeyEnvelope::Storage(storage_key) => { target_categorized_fetch_keys .headers - .insert(HeaderMemorizerKey::new( + .insert(EvmHeaderKey::new( storage_key.chain_id, storage_key.block_number, )); target_categorized_fetch_keys.storage.insert(storage_key); } - FetchKeyEnvelope::Tx(tx_key) => { + EvmFetchKeyEnvelope::Tx(tx_key) => { target_categorized_fetch_keys .headers - .insert(HeaderMemorizerKey::new( - tx_key.chain_id, - tx_key.block_number, - )); - target_categorized_fetch_keys.txs.insert(tx_key); + .insert(EvmHeaderKey::new(tx_key.chain_id, tx_key.block_number)); + target_categorized_fetch_keys.block_txs.insert(tx_key); } - FetchKeyEnvelope::TxReceipt(tx_receipt_key) => { + EvmFetchKeyEnvelope::TxReceipt(tx_receipt_key) => { target_categorized_fetch_keys .headers - .insert(HeaderMemorizerKey::new( + .insert(EvmHeaderKey::new( tx_receipt_key.chain_id, tx_receipt_key.block_number, )); target_categorized_fetch_keys - .tx_receipts + .block_receipts .insert(tx_receipt_key); } } @@ -106,12 +103,12 @@ pub fn categorize_fetch_keys( /// Key for fetching block header from provider. #[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] -pub struct HeaderMemorizerKey { +pub struct EvmHeaderKey { pub chain_id: ChainId, pub block_number: BlockNumber, } -impl<'de> Deserialize<'de> for HeaderMemorizerKey { +impl<'de> Deserialize<'de> for EvmHeaderKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -124,14 +121,14 @@ impl<'de> Deserialize<'de> for HeaderMemorizerKey { let helper = Helper::deserialize(deserializer)?; - Ok(HeaderMemorizerKey { + Ok(EvmHeaderKey { chain_id: ChainId::from_numeric_id(helper.chain_id).expect("invalid deserialize"), block_number: helper.block_number, }) } } -impl HeaderMemorizerKey { +impl EvmHeaderKey { pub fn new(chain_id: ChainId, block_number: BlockNumber) -> Self { Self { chain_id, @@ -150,13 +147,13 @@ impl HeaderMemorizerKey { /// Key for fetching account from provider. #[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] -pub struct AccountMemorizerKey { +pub struct EvmAccountKey { pub chain_id: ChainId, pub block_number: BlockNumber, pub address: Address, } -impl<'de> Deserialize<'de> for AccountMemorizerKey { +impl<'de> Deserialize<'de> for EvmAccountKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -170,7 +167,7 @@ impl<'de> Deserialize<'de> for AccountMemorizerKey { let helper = Helper::deserialize(deserializer)?; - Ok(AccountMemorizerKey { + Ok(EvmAccountKey { chain_id: ChainId::from_numeric_id(helper.chain_id).expect("invalid deserialize"), block_number: helper.block_number, address: helper.address, @@ -178,7 +175,7 @@ impl<'de> Deserialize<'de> for AccountMemorizerKey { } } -impl AccountMemorizerKey { +impl EvmAccountKey { pub fn new(chain_id: ChainId, block_number: BlockNumber, address: Address) -> Self { Self { chain_id, @@ -199,14 +196,14 @@ impl AccountMemorizerKey { /// Key for fetching storage value from provider. #[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] -pub struct StorageMemorizerKey { +pub struct EvmStorageKey { pub chain_id: ChainId, pub block_number: BlockNumber, pub address: Address, pub key: StorageKey, } -impl<'de> Deserialize<'de> for StorageMemorizerKey { +impl<'de> Deserialize<'de> for EvmStorageKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -221,7 +218,7 @@ impl<'de> Deserialize<'de> for StorageMemorizerKey { let helper = Helper::deserialize(deserializer)?; - Ok(StorageMemorizerKey { + Ok(EvmStorageKey { chain_id: ChainId::from_numeric_id(helper.chain_id).expect("invalid deserialize"), block_number: helper.block_number, address: helper.address, @@ -230,7 +227,7 @@ impl<'de> Deserialize<'de> for StorageMemorizerKey { } } -impl StorageMemorizerKey { +impl EvmStorageKey { pub fn new( chain_id: ChainId, block_number: BlockNumber, @@ -258,13 +255,13 @@ impl StorageMemorizerKey { /// Key for fetching transaction from provider. #[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] -pub struct TxMemorizerKey { +pub struct EvmBlockTxKey { pub chain_id: ChainId, pub block_number: BlockNumber, - pub tx_index: u64, + pub index: u64, } -impl<'de> Deserialize<'de> for TxMemorizerKey { +impl<'de> Deserialize<'de> for EvmBlockTxKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -273,25 +270,25 @@ impl<'de> Deserialize<'de> for TxMemorizerKey { struct Helper { chain_id: u128, block_number: BlockNumber, - tx_index: u64, + index: u64, } let helper = Helper::deserialize(deserializer)?; - Ok(TxMemorizerKey { + Ok(EvmBlockTxKey { chain_id: ChainId::from_numeric_id(helper.chain_id).expect("invalid deserialize"), block_number: helper.block_number, - tx_index: helper.tx_index, + index: helper.index, }) } } -impl TxMemorizerKey { - pub fn new(chain_id: ChainId, block_number: BlockNumber, tx_index: u64) -> Self { +impl EvmBlockTxKey { + pub fn new(chain_id: ChainId, block_number: BlockNumber, index: u64) -> Self { Self { chain_id, block_number, - tx_index, + index, } } @@ -300,20 +297,20 @@ impl TxMemorizerKey { keccak.update([TransactionsCollectionType::Transactions.to_u8()]); keccak.update(self.chain_id.to_be_bytes()); keccak.update(self.block_number.to_be_bytes()); - keccak.update(self.tx_index.to_be_bytes()); + keccak.update(self.index.to_be_bytes()); keccak.finalize() } } /// Key for fetching transaction receipt from provider. #[derive(Debug, Clone, Serialize, PartialEq, Eq, Hash)] -pub struct TxReceiptMemorizerKey { +pub struct EvmBlockReceiptKey { pub chain_id: ChainId, pub block_number: BlockNumber, - pub tx_index: u64, + pub index: u64, } -impl<'de> Deserialize<'de> for TxReceiptMemorizerKey { +impl<'de> Deserialize<'de> for EvmBlockReceiptKey { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, @@ -322,25 +319,25 @@ impl<'de> Deserialize<'de> for TxReceiptMemorizerKey { struct Helper { chain_id: u128, block_number: BlockNumber, - tx_index: u64, + index: u64, } let helper = Helper::deserialize(deserializer)?; - Ok(TxReceiptMemorizerKey { + Ok(EvmBlockReceiptKey { chain_id: ChainId::from_numeric_id(helper.chain_id).expect("invalid deserialize"), block_number: helper.block_number, - tx_index: helper.tx_index, + index: helper.index, }) } } -impl TxReceiptMemorizerKey { - pub fn new(chain_id: ChainId, block_number: BlockNumber, tx_index: u64) -> Self { +impl EvmBlockReceiptKey { + pub fn new(chain_id: ChainId, block_number: BlockNumber, index: u64) -> Self { Self { chain_id, block_number, - tx_index, + index, } } @@ -349,27 +346,27 @@ impl TxReceiptMemorizerKey { keccak.update([TransactionsCollectionType::TransactionReceipts.to_u8()]); keccak.update(self.chain_id.to_be_bytes()); keccak.update(self.block_number.to_be_bytes()); - keccak.update(self.tx_index.to_be_bytes()); + keccak.update(self.index.to_be_bytes()); keccak.finalize() } } #[derive(Hash, Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] #[serde(tag = "type", content = "key")] -pub enum FetchKeyEnvelope { - #[serde(rename = "HeaderMemorizerKey")] - Header(HeaderMemorizerKey), - #[serde(rename = "AccountMemorizerKey")] - Account(AccountMemorizerKey), - #[serde(rename = "StorageMemorizerKey")] - Storage(StorageMemorizerKey), - #[serde(rename = "TxMemorizerKey")] - Tx(TxMemorizerKey), - #[serde(rename = "TxReceiptMemorizerKey")] - TxReceipt(TxReceiptMemorizerKey), +pub enum EvmFetchKeyEnvelope { + #[serde(rename = "EvmHeaderKey")] + Header(EvmHeaderKey), + #[serde(rename = "EvmAccountKey")] + Account(EvmAccountKey), + #[serde(rename = "EvmStorageKey")] + Storage(EvmStorageKey), + #[serde(rename = "EvmBlockTxKey")] + Tx(EvmBlockTxKey), + #[serde(rename = "EvmBlockReceiptKey")] + TxReceipt(EvmBlockReceiptKey), } -impl FromStr for FetchKeyEnvelope { +impl FromStr for EvmFetchKeyEnvelope { type Err = anyhow::Error; fn from_str(s: &str) -> Result { @@ -382,13 +379,13 @@ impl FromStr for FetchKeyEnvelope { let block_number = parts[1].parse()?; match parts.len() { - 2 => Ok(FetchKeyEnvelope::Header(HeaderMemorizerKey { + 2 => Ok(EvmFetchKeyEnvelope::Header(EvmHeaderKey { chain_id, block_number, })), 3 => { let address = parts[2].parse()?; - Ok(FetchKeyEnvelope::Account(AccountMemorizerKey { + Ok(EvmFetchKeyEnvelope::Account(EvmAccountKey { chain_id, block_number, address, @@ -397,7 +394,7 @@ impl FromStr for FetchKeyEnvelope { 4 => { let address = parts[2].parse()?; let key = parts[3].parse()?; - Ok(FetchKeyEnvelope::Storage(StorageMemorizerKey { + Ok(EvmFetchKeyEnvelope::Storage(EvmStorageKey { chain_id, block_number, address, @@ -409,15 +406,15 @@ impl FromStr for FetchKeyEnvelope { } } -impl FetchKeyEnvelope { +impl EvmFetchKeyEnvelope { /// Get the chain id from the fetch key. pub fn get_chain_id(&self) -> ChainId { match self { - FetchKeyEnvelope::Header(key) => key.chain_id, - FetchKeyEnvelope::Account(key) => key.chain_id, - FetchKeyEnvelope::Storage(key) => key.chain_id, - FetchKeyEnvelope::Tx(key) => key.chain_id, - FetchKeyEnvelope::TxReceipt(key) => key.chain_id, + EvmFetchKeyEnvelope::Header(key) => key.chain_id, + EvmFetchKeyEnvelope::Account(key) => key.chain_id, + EvmFetchKeyEnvelope::Storage(key) => key.chain_id, + EvmFetchKeyEnvelope::Tx(key) => key.chain_id, + EvmFetchKeyEnvelope::TxReceipt(key) => key.chain_id, } } } @@ -431,7 +428,7 @@ mod tests { #[test] fn test_hash_header_key() { - let header_key = HeaderMemorizerKey::new(ChainId::EthereumMainnet, 100); + let header_key = EvmHeaderKey::new(ChainId::EthereumMainnet, 100); let header_key_hash = header_key.hash_key(); assert_eq!( header_key_hash, @@ -441,7 +438,7 @@ mod tests { #[test] fn test_hash_account_key() { - let account_key = AccountMemorizerKey::new(ChainId::EthereumMainnet, 100, Address::ZERO); + let account_key = EvmAccountKey::new(ChainId::EthereumMainnet, 100, Address::ZERO); let account_key_hash = account_key.hash_key(); assert_eq!( account_key_hash, @@ -452,7 +449,7 @@ mod tests { #[test] fn test_hash_storage_key() { let storage_key = - StorageMemorizerKey::new(ChainId::EthereumMainnet, 100, Address::ZERO, B256::ZERO); + EvmStorageKey::new(ChainId::EthereumMainnet, 100, Address::ZERO, B256::ZERO); let storage_key_hash = storage_key.hash_key(); assert_eq!( storage_key_hash, @@ -462,7 +459,7 @@ mod tests { #[test] fn test_hash_tx_key() { - let tx_key = TxMemorizerKey::new(ChainId::EthereumMainnet, 100, 1); + let tx_key = EvmBlockTxKey::new(ChainId::EthereumMainnet, 100, 1); let tx_key_hash = tx_key.hash_key(); assert_eq!( tx_key_hash, @@ -472,7 +469,7 @@ mod tests { #[test] fn test_hash_tx_receipt_key() { - let tx_receipt = TxReceiptMemorizerKey::new(ChainId::EthereumMainnet, 100, 1); + let tx_receipt = EvmBlockReceiptKey::new(ChainId::EthereumMainnet, 100, 1); let tx_receipt_hash = tx_receipt.hash_key(); assert_eq!( tx_receipt_hash, @@ -483,21 +480,21 @@ mod tests { #[test] fn test_parse_json_header_key() { let json = - r#"{"type": "HeaderMemorizerKey", "key": {"chain_id": 11155111, "block_number": 100}}"#; - let parsed: FetchKeyEnvelope = serde_json::from_str(json).unwrap(); + r#"{"type": "EvmHeaderKey", "key": {"chain_id": 11155111, "block_number": 100}}"#; + let parsed: EvmFetchKeyEnvelope = serde_json::from_str(json).unwrap(); assert_eq!( parsed, - FetchKeyEnvelope::Header(HeaderMemorizerKey::new(ChainId::EthereumSepolia, 100)) + EvmFetchKeyEnvelope::Header(EvmHeaderKey::new(ChainId::EthereumSepolia, 100)) ); } #[test] fn test_parse_json_account_key() { - let json = r#"{"type": "AccountMemorizerKey", "key": {"chain_id": 1, "block_number": 100, "address": "0x0000000000000000000000000000000000000000"}}"#; - let parsed: FetchKeyEnvelope = serde_json::from_str(json).unwrap(); + let json = r#"{"type": "EvmAccountKey", "key": {"chain_id": 1, "block_number": 100, "address": "0x0000000000000000000000000000000000000000"}}"#; + let parsed: EvmFetchKeyEnvelope = serde_json::from_str(json).unwrap(); assert_eq!( parsed, - FetchKeyEnvelope::Account(AccountMemorizerKey::new( + EvmFetchKeyEnvelope::Account(EvmAccountKey::new( ChainId::EthereumMainnet, 100, Address::ZERO @@ -507,11 +504,11 @@ mod tests { #[test] fn test_parse_json_storage_key() { - let json = r#"{"type": "StorageMemorizerKey", "key": {"chain_id": 1, "block_number": 100, "address": "0x0000000000000000000000000000000000000000", "key": "0x0000000000000000000000000000000000000000000000000000000000000000"}}"#; - let parsed: FetchKeyEnvelope = serde_json::from_str(json).unwrap(); + let json = r#"{"type": "EvmStorageKey", "key": {"chain_id": 1, "block_number": 100, "address": "0x0000000000000000000000000000000000000000", "key": "0x0000000000000000000000000000000000000000000000000000000000000000"}}"#; + let parsed: EvmFetchKeyEnvelope = serde_json::from_str(json).unwrap(); assert_eq!( parsed, - FetchKeyEnvelope::Storage(StorageMemorizerKey::new( + EvmFetchKeyEnvelope::Storage(EvmStorageKey::new( ChainId::EthereumMainnet, 100, Address::ZERO, @@ -522,21 +519,22 @@ mod tests { #[test] fn test_parse_json_tx_key() { - let json = r#"{"type": "TxMemorizerKey", "key": {"chain_id": 1, "block_number": 100, "tx_index": 1}}"#; - let parsed: FetchKeyEnvelope = serde_json::from_str(json).unwrap(); + let json = + r#"{"type": "EvmBlockTxKey", "key": {"chain_id": 1, "block_number": 100, "index": 1}}"#; + let parsed: EvmFetchKeyEnvelope = serde_json::from_str(json).unwrap(); assert_eq!( parsed, - FetchKeyEnvelope::Tx(TxMemorizerKey::new(ChainId::EthereumMainnet, 100, 1)) + EvmFetchKeyEnvelope::Tx(EvmBlockTxKey::new(ChainId::EthereumMainnet, 100, 1)) ); } #[test] fn test_parse_json_tx_receipt_key() { - let json = r#"{"type": "TxReceiptMemorizerKey", "key": {"chain_id": 1, "block_number": 100, "tx_index": 1}}"#; - let parsed: FetchKeyEnvelope = serde_json::from_str(json).unwrap(); + let json = r#"{"type": "EvmBlockReceiptKey", "key": {"chain_id": 1, "block_number": 100, "index": 1}}"#; + let parsed: EvmFetchKeyEnvelope = serde_json::from_str(json).unwrap(); assert_eq!( parsed, - FetchKeyEnvelope::TxReceipt(TxReceiptMemorizerKey::new( + EvmFetchKeyEnvelope::TxReceipt(EvmBlockReceiptKey::new( ChainId::EthereumMainnet, 100, 1 diff --git a/hdp/src/provider/starknet/mod.rs b/hdp/src/provider/starknet/mod.rs index a8c241cb..93a521a5 100644 --- a/hdp/src/provider/starknet/mod.rs +++ b/hdp/src/provider/starknet/mod.rs @@ -1 +1,3 @@ -pub struct StarknetProvider {} +pub mod provider; +pub mod rpc; +pub mod types; diff --git a/hdp/src/provider/starknet/provider.rs b/hdp/src/provider/starknet/provider.rs new file mode 100644 index 00000000..d9fbdf45 --- /dev/null +++ b/hdp/src/provider/starknet/provider.rs @@ -0,0 +1,121 @@ +use std::{collections::HashMap, time::Instant}; + +use alloy::primitives::BlockNumber; +use itertools::Itertools; +use starknet_types_core::felt::Felt; +use tracing::info; + +use crate::provider::{config::ProviderConfig, error::ProviderError, indexer::Indexer}; + +use super::{rpc::RpcProvider, types::GetProofOutput}; + +type AccountProofsResult = Result, ProviderError>; +type StorageProofsResult = Result, ProviderError>; + +pub struct StarknetProvider { + /// Account and storage trie provider + pub(crate) rpc_provider: RpcProvider, + /// Header provider + //TODO: indexer is not supported for starknet yet + pub(crate) _header_provider: Indexer, +} + +#[cfg(feature = "test_utils")] +impl Default for StarknetProvider { + fn default() -> Self { + Self::new(&ProviderConfig::default()) + } +} + +impl StarknetProvider { + pub fn new(config: &ProviderConfig) -> Self { + let rpc_provider = RpcProvider::new(config.provider_url.to_owned(), config.max_requests); + let indexer = Indexer::new(config.chain_id); + Self { + rpc_provider, + _header_provider: indexer, + } + } + + /// Fetches the account proofs for the given block range. + /// The account proofs are fetched from the RPC provider. + /// + /// Return: + /// - Account proofs mapped by block number + pub async fn get_range_of_account_proofs( + &self, + from_block: BlockNumber, + to_block: BlockNumber, + increment: u64, + address: Felt, + ) -> AccountProofsResult { + let start_fetch = Instant::now(); + + let target_blocks_batch: Vec> = + self._chunk_block_range(from_block, to_block, increment); + + let mut fetched_accounts_proofs_with_blocks_map = HashMap::new(); + for target_blocks in target_blocks_batch { + fetched_accounts_proofs_with_blocks_map.extend( + self.rpc_provider + .get_account_proofs(target_blocks, address) + .await?, + ); + } + + let duration = start_fetch.elapsed(); + info!("time taken (Account Proofs Fetch): {:?}", duration); + + Ok(fetched_accounts_proofs_with_blocks_map) + } + + /// Fetches the storage proofs for the given block range. + /// The storage proofs are fetched from the RPC provider. + /// + /// Return: + /// - Storage proofs mapped by block number + pub async fn get_range_of_storage_proofs( + &self, + from_block: BlockNumber, + to_block: BlockNumber, + increment: u64, + address: Felt, + storage_slot: Felt, + ) -> StorageProofsResult { + let start_fetch = Instant::now(); + + let target_blocks_batch: Vec> = + self._chunk_block_range(from_block, to_block, increment); + + let mut processed_accounts = HashMap::new(); + for target_blocks in target_blocks_batch { + processed_accounts.extend( + self.rpc_provider + .get_storage_proofs(target_blocks, address, storage_slot) + .await?, + ); + } + + let duration = start_fetch.elapsed(); + info!("time taken (Storage Proofs Fetch): {:?}", duration); + + Ok(processed_accounts) + } + + /// Chunks the block range into smaller ranges of 800 blocks. + /// This is to avoid fetching too many blocks at once from the RPC provider. + /// This is meant to use with data lake definition, which have sequential block numbers + pub(crate) fn _chunk_block_range( + &self, + from_block: BlockNumber, + to_block: BlockNumber, + increment: u64, + ) -> Vec> { + (from_block..=to_block) + .step_by(increment as usize) + .chunks(800) + .into_iter() + .map(|chunk| chunk.collect()) + .collect() + } +} diff --git a/hdp/src/provider/starknet/rpc.rs b/hdp/src/provider/starknet/rpc.rs new file mode 100644 index 00000000..bfa6f75a --- /dev/null +++ b/hdp/src/provider/starknet/rpc.rs @@ -0,0 +1,284 @@ +use alloy::primitives::BlockNumber; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, + time::Instant, +}; + +use futures::future::join_all; +use reqwest::{Client, Url}; +use serde_json::json; +use starknet_types_core::felt::Felt; +use tokio::sync::{ + mpsc::{self, Sender}, + RwLock, +}; +use tracing::{debug, error}; + +use crate::provider::error::RpcProviderError; + +use super::types::GetProofOutput; + +/// !Note: have to use pathfinder node as we need `pathfinder_getProof` +pub struct RpcProvider { + client: reqwest::Client, + url: Url, + chunk_size: u64, +} + +impl RpcProvider { + pub fn new(rpc_url: Url, chunk_size: u64) -> Self { + Self { + client: Client::new(), + url: rpc_url, + chunk_size, + } + } + + /// Get account with proof in given vector of blocks + pub async fn get_account_proofs( + &self, + blocks: Vec, + address: Felt, + ) -> Result, RpcProviderError> { + self.get_proofs(blocks, address, None).await + } + + /// Get storage with proof in given vector of blocks and slot + pub async fn get_storage_proofs( + &self, + block_range: Vec, + address: Felt, + storage_key: Felt, + ) -> Result, RpcProviderError> { + self.get_proofs(block_range, address, Some(storage_key)) + .await + } + + async fn get_proofs( + &self, + blocks: Vec, + address: Felt, + storage_key: Option, + ) -> Result, RpcProviderError> { + let start_fetch = Instant::now(); + let (rpc_sender, mut rx) = mpsc::channel::<(BlockNumber, GetProofOutput)>(32); + self.spawn_proof_fetcher(rpc_sender, blocks, address, storage_key); + + let mut fetched_proofs = HashMap::new(); + while let Some((block_number, proof)) = rx.recv().await { + fetched_proofs.insert(block_number, proof); + } + let duration = start_fetch.elapsed(); + debug!("time taken (Fetch): {:?}", duration); + + Ok(fetched_proofs) + } + + fn spawn_proof_fetcher( + &self, + rpc_sender: Sender<(BlockNumber, GetProofOutput)>, + blocks: Vec, + address: Felt, + storage_key: Option, + ) { + let chunk_size = self.chunk_size; + let provider_clone = self.client.clone(); + let target_blocks_length = blocks.len(); + let url = self.url.clone(); + + debug!( + "fetching proofs for {}, with chunk size: {}", + address, chunk_size + ); + + tokio::spawn(async move { + let mut try_count = 0; + let blocks_map = Arc::new(RwLock::new(HashSet::::new())); + + while blocks_map.read().await.len() < target_blocks_length { + try_count += 1; + if try_count > 50 { + panic!("❗️❗️❗️ Too many retries, failed to fetch all blocks") + } + let fetched_blocks_clone = blocks_map.read().await.clone(); + + let blocks_to_fetch: Vec = blocks + .iter() + .filter(|block_number| !fetched_blocks_clone.contains(block_number)) + .take(chunk_size as usize) + .cloned() + .collect(); + + let fetch_futures = blocks_to_fetch + .into_iter() + .map(|block_number| { + let fetched_blocks_clone = blocks_map.clone(); + let rpc_sender = rpc_sender.clone(); + let provider_clone = provider_clone.clone(); + let url = url.clone(); + async move { + let proof = pathfinder_get_proof( + &provider_clone, + url, + address, + block_number, + storage_key, + ) + .await; + handle_proof_result( + proof, + block_number, + fetched_blocks_clone, + rpc_sender, + ) + .await; + } + }) + .collect::>(); + + join_all(fetch_futures).await; + } + }); + } +} + +/// Fetches proof (account or storage) for a given block number +async fn pathfinder_get_proof( + provider: &reqwest::Client, + url: Url, + address: Felt, + block_number: BlockNumber, + storage_key: Option, +) -> Result { + let mut keys = Vec::new(); + if let Some(key) = storage_key { + keys.push(key.to_hex_string()); + } + + let request = json!({ + "jsonrpc": "2.0", + "id": "0", + "method": "pathfinder_getProof", + "params": { + "block_id": {"block_number": block_number}, + "contract_address": format!("{}", address.to_hex_string()), + "keys": keys + } + }); + + let response = provider.post(url).json(&request).send().await?; + let response_json = + serde_json::from_str::(&response.text().await?)?["result"].clone(); + println!("response_json: {:?}", response_json); + let get_proof_output: GetProofOutput = serde_json::from_value(response_json)?; + Ok(get_proof_output) +} + +async fn handle_proof_result( + proof: Result, + block_number: BlockNumber, + blocks_map: Arc>>, + rpc_sender: Sender<(BlockNumber, GetProofOutput)>, +) { + match proof { + Ok(proof) => { + blocks_map.write().await.insert(block_number); + rpc_sender.send((block_number, proof)).await.unwrap(); + } + Err(e) => { + error!("❗️❗️❗️ Error fetching proof: {:?}", e); + } + } +} +#[cfg(test)] +mod tests { + use core::str::FromStr; + + use super::*; + use reqwest::Url; + + const PATHFINDER_URL: &str = "https://pathfinder.sepolia.iosis.tech/"; + + fn test_provider() -> RpcProvider { + RpcProvider::new(Url::from_str(PATHFINDER_URL).unwrap(), 100) + } + + #[tokio::test] + async fn test_get_100_range_storage_with_proof() { + let target_block_start = 56400; + let target_block_end = 56500; + let target_block_range = (target_block_start..=target_block_end).collect::>(); + let provider = test_provider(); + let proof = provider + .get_storage_proofs( + target_block_range.clone(), + Felt::from_str( + "0x017E2D0662675DD83B4B58A0A659EAFA131FDD01FA6DABD5002D8815DD2D17A5", + ) + .unwrap(), + Felt::from_str( + "0x004C4FB1AB068F6039D5780C68DD0FA2F8742CCEB3426D19667778CA7F3518A9", + ) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(proof.len(), target_block_range.len()); + let output = proof.get(&target_block_start).unwrap(); + + assert_eq!( + output.state_commitment.unwrap(), + Felt::from_str("0x598cf91d9a3a7176d01926e8442b8bd83299168f723cb2d52080e895400d9a1") + .unwrap() + ); + + assert_eq!(output.contract_proof.len(), 17); + + assert_eq!( + output.class_commitment.unwrap(), + Felt::from_str("0x324d06b207f2891ef395ba1e7a0ef92b61a5772a294a289362dc37b0469c453") + .unwrap() + ); + + assert_eq!( + output.contract_data.clone().unwrap().storage_proofs[0].len(), + 5 + ); + } + + #[tokio::test] + async fn test_get_100_range_account_with_proof() { + let target_block_start = 156600; + let target_block_end = 156700; + let target_block_range = (target_block_start..=target_block_end).collect::>(); + let provider = test_provider(); + let proof = provider + .get_account_proofs( + target_block_range.clone(), + Felt::from_str("0x23371b227eaecd8e8920cd429d2cd0f3fee6abaacca08d3ab82a7cdd") + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(proof.len(), target_block_range.len()); + let output = proof.get(&target_block_start).unwrap(); + println!("Proof: {:?}", output); + assert_eq!( + output.state_commitment.unwrap(), + Felt::from_str("0x26da0f5f0849cf69b4872ef5dced3ec68ce28c5e3f53207280113abb7feb158") + .unwrap() + ); + assert_eq!(output.contract_proof.len(), 23); + + assert_eq!( + output.class_commitment.unwrap(), + Felt::from_str("0x46c1a0374b8ccf8d928e62ef40974304732c8a28f10b2c494adfabfcff0fa0a") + .unwrap() + ); + + assert!(output.contract_data.is_none()); + } +} diff --git a/hdp/src/provider/starknet/types.rs b/hdp/src/provider/starknet/types.rs new file mode 100644 index 00000000..a827823b --- /dev/null +++ b/hdp/src/provider/starknet/types.rs @@ -0,0 +1,82 @@ +use serde::{Deserialize, Serialize}; +use serde_with::skip_serializing_none; +use starknet_types_core::{felt::Felt, hash::StarkHash}; + +/// Codebase is from + +/// Holds the membership/non-membership of a contract and its associated +/// contract contract if the contract exists. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[skip_serializing_none] +pub struct GetProofOutput { + /// The global state commitment for Starknet 0.11.0 blocks onwards, if + /// absent the hash of the first node in the + /// [contract_proof](GetProofOutput#contract_proof) is the global state + /// commitment. + pub state_commitment: Option, + /// Required to verify that the hash of the class commitment and the root of + /// the [contract_proof](GetProofOutput::contract_proof) matches the + /// [state_commitment](Self#state_commitment). Present only for Starknet + /// blocks 0.11.0 onwards. + pub class_commitment: Option, + + /// Membership / Non-membership proof for the queried contract + pub contract_proof: Vec, + + /// Additional contract data if it exists. + pub contract_data: Option, +} + +/// A node in a Starknet patricia-merkle trie. +/// +/// See pathfinders merkle-tree crate for more information. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum TrieNode { + #[serde(rename = "binary")] + Binary { left: Felt, right: Felt }, + #[serde(rename = "edge")] + Edge { child: Felt, path: Path }, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Path { + len: u64, + value: String, +} + +impl TrieNode { + pub fn hash(&self) -> Felt { + match self { + TrieNode::Binary { left, right } => H::hash(left, right), + TrieNode::Edge { child, path } => { + let bytes: [u8; 32] = path.value.as_bytes().try_into().unwrap(); + let mut length = [0; 32]; + // Safe as len() is guaranteed to be <= 251 + length[31] = bytes.len() as u8; + + let length = Felt::from_bytes_be(&length); + let path = Felt::from_bytes_be(&bytes); + H::hash(child, &path) + length + } + } + } +} + +/// Holds the data and proofs for a specific contract. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ContractData { + /// Required to verify the contract state hash to contract root calculation. + class_hash: Felt, + /// Required to verify the contract state hash to contract root calculation. + nonce: Felt, + + /// Root of the Contract state tree + root: Felt, + + /// This is currently just a constant = 0, however it might change in the + /// future. + contract_state_hash_version: Felt, + + /// The proofs associated with the queried storage values + pub storage_proofs: Vec>, +} diff --git a/hdp/src/provider/types.rs b/hdp/src/provider/types.rs index 6c610e9d..836a4a66 100644 --- a/hdp/src/provider/types.rs +++ b/hdp/src/provider/types.rs @@ -5,9 +5,10 @@ use std::collections::HashSet; +use crate::primitives::processed_types::block_proofs::MMRWithHeader; use crate::primitives::processed_types::{ - account::ProcessedAccount, header::ProcessedHeader, mmr::MMRMeta, receipt::ProcessedReceipt, - storage::ProcessedStorage, transaction::ProcessedTransaction, + account::ProcessedAccount, receipt::ProcessedReceipt, storage::ProcessedStorage, + transaction::ProcessedTransaction, }; use alloy::primitives::U256; @@ -73,8 +74,8 @@ impl FetchedTransactionReceiptProof { pub struct FetchedDatalake { /// Targeted datalake's compiled results pub values: Vec, - /// Headers related to the datalake - pub headers: HashSet, + /// mmr_with_headers related to the datalake + pub mmr_with_headers: HashSet, /// Accounts related to the datalake pub accounts: HashSet, /// Storages related to the datalake @@ -83,6 +84,4 @@ pub struct FetchedDatalake { pub transactions: HashSet, /// Transaction receipts related to the datalake pub transaction_receipts: HashSet, - /// MMR meta data related to the headers - pub mmr_metas: HashSet, } diff --git a/justfile b/justfile new file mode 100644 index 00000000..c1730a61 --- /dev/null +++ b/justfile @@ -0,0 +1,26 @@ +# Set environment variable +export CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE := "true" + +# Run rustfmt to check the code formatting without making changes +format: + cargo fmt -- --check + +# Clean up the project by removing the target directory +clean: + cargo clean + +# Run clippy to catch common mistakes and improve your Rust code +clippy: + cargo clippy --all-targets --all-features -- -Dwarnings + +# Generate documentation for the project +docs: + cargo doc --no-deps + +# Execute all unit tests in the workspace +test: + cargo llvm-cov nextest --features test_utils + +# Run the entire CI pipeline including format, clippy, docs, and test checks +run-ci-flow: format clippy docs test + @echo "CI flow completed" diff --git a/request.json b/request.json index e5ce8cca..d5824eb7 100644 --- a/request.json +++ b/request.json @@ -26,6 +26,34 @@ "valueToCompare": "1000000000000000000" } } + }, + { + "type": "DatalakeCompute", + "datalake": { + "type": "BlockSampled", + "chainId": "ETHEREUM_MAINNET", + "blockRangeStart": 100, + "blockRangeEnd": 110, + "increment": 1, + "sampledProperty": "header.number" + }, + "compute": { + "aggregateFnId": "avg" + } + }, + { + "type": "DatalakeCompute", + "datalake": { + "type": "BlockSampled", + "chainId": "ETHEREUM_SEPOLIA", + "blockRangeStart": 6375109, + "blockRangeEnd": 6375111, + "increment": 1, + "sampledProperty": "storage.0xaFE8A72C86d5895DD6616daB26d4b736Cf22472f.0x0000000000000000000000000000000000000000000000000000000000000010" + }, + "compute": { + "aggregateFnId": "sum" + } } ], "destinationChainId": "ETHEREUM_SEPOLIA"