diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7fdb43d..2265daa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,4 +53,4 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} files: ./lcov.info - fail_ci_if_error: true \ No newline at end of file + fail_ci_if_error: true diff --git a/Cargo.lock b/Cargo.lock index e4606c9..1a1ef0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,16 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" dependencies = [ - "gimli", + "gimli 0.27.3", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli 0.28.1", ] [[package]] @@ -313,12 +322,38 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line 0.21.0", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object 0.32.1", + "rustc-demangle", +] + [[package]] name = "bandersnatch_vrfs" version = "0.0.1" @@ -373,6 +408,16 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" +dependencies = [ + "bincode_derive", + "serde", +] + [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -381,6 +426,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + [[package]] name = "bindgen" version = "0.65.1" @@ -537,9 +591,12 @@ dependencies = [ "mp-commitments", "mp-felt", "mp-hashers", - "mp-transactions", "parity-scale-codec", "parking_lot", + "pathfinder-common", + "pathfinder-crypto", + "pathfinder-merkle-tree", + "pathfinder-storage", "rand 0.8.5", "rocksdb", "rustc-hex", @@ -711,7 +768,7 @@ dependencies = [ "anyhow", "ark-ff", "ark-std", - "bincode 2.0.0-rc.3", + "bincode 2.0.0-rc.3 (git+https://github.com/bincode-org/bincode.git?tag=v2.0.0-rc.3)", "bitvec", "cairo-felt", "cairo-lang-casm", @@ -802,6 +859,32 @@ dependencies = [ "rand_chacha 0.3.1", ] +[[package]] +name = "const-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5241cd7938b1b415942e943ea96f615953d500b50347b505b0b507080bad5a6f" + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -820,6 +903,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -960,6 +1053,12 @@ dependencies = [ "syn 2.0.40", ] +[[package]] +name = "data-encoding" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" + [[package]] name = "deranged" version = "0.3.10" @@ -967,6 +1066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ "powerfmt", + "serde", ] [[package]] @@ -993,6 +1093,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deunicode" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" + [[package]] name = "digest" version = "0.8.1" @@ -1039,6 +1145,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dummy" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e57e12b69e57fad516e01e2b3960f122696fdb13420e1a88ed8e210316f2876" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "dyn-clonable" version = "0.9.0" @@ -1086,6 +1204,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_logger" version = "0.10.1" @@ -1121,6 +1248,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fake" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" +dependencies = [ + "deunicode", + "dummy", + "rand 0.8.5", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -1133,6 +1271,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "2.0.1" @@ -1180,6 +1324,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1267,6 +1426,12 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + [[package]] name = "futures-util" version = "0.3.29" @@ -1348,12 +1513,37 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hash-db" version = "0.16.0" @@ -1398,6 +1588,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.3", +] + [[package]] name = "heck" version = "0.4.1" @@ -1435,12 +1634,83 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -1537,6 +1807,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.3", + "serde", ] [[package]] @@ -1574,6 +1845,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "is-terminal" version = "0.4.9" @@ -1627,6 +1904,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types", + "tiny-keccak", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1720,6 +2007,17 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libsqlite3-sys" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-sys" version = "1.1.12" @@ -1853,6 +2151,34 @@ dependencies = [ "zeroize", ] +[[package]] +name = "metrics" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b9b8653cec6897f73b519a43fba5ee3d50f62fe9af80b428accdcc093b4a849" +dependencies = [ + "ahash 0.7.7", + "metrics-macros", + "portable-atomic 0.3.20", +] + +[[package]] +name = "metrics-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731f8ecebd9f3a4aa847dfe75455e4757a45da40a7793d2f0b1f9b6ed18b23f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1868,6 +2194,17 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "mp-commitments" version = "0.6.0" @@ -1957,6 +2294,24 @@ dependencies = [ "starknet_api", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nom" version = "7.1.3" @@ -2046,6 +2401,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.30.4" @@ -2058,6 +2422,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -2077,18 +2450,62 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "parity-scale-codec" -version = "3.6.9" +name = "openssl" +version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ - "arrayvec 0.7.4", - "bitvec", - "byte-slice-cast", - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.40", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", ] [[package]] @@ -2132,6 +2549,126 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathfinder-common" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "bitvec", + "fake", + "metrics", + "num-bigint", + "paste", + "pathfinder-crypto", + "primitive-types", + "rand 0.8.5", + "semver", + "serde", + "serde_json", + "serde_with 3.4.0", + "sha3", + "thiserror", + "vergen", +] + +[[package]] +name = "pathfinder-crypto" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "ark-ff", + "bitvec", + "fake", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "pathfinder-ethereum" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "async-trait", + "const-decoder", + "hex", + "keccak-hash", + "pathfinder-common", + "pathfinder-crypto", + "primitive-types", + "reqwest", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "pathfinder-merkle-tree" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "bitvec", + "pathfinder-common", + "pathfinder-crypto", + "pathfinder-storage", + "rand 0.8.5", + "starknet-gateway-types", + "thiserror", + "tracing", +] + +[[package]] +name = "pathfinder-serde" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "num-bigint", + "pathfinder-common", + "pathfinder-crypto", + "primitive-types", + "serde", + "serde_json", + "serde_with 3.4.0", +] + +[[package]] +name = "pathfinder-storage" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "base64 0.13.1", + "bincode 2.0.0-rc.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitvec", + "const_format", + "data-encoding", + "fake", + "hex", + "lazy_static", + "pathfinder-common", + "pathfinder-crypto", + "pathfinder-ethereum", + "pathfinder-serde", + "primitive-types", + "r2d2", + "r2d2_sqlite", + "rand 0.8.5", + "rusqlite", + "serde", + "serde_json", + "serde_with 3.4.0", + "sha3", + "starknet-gateway-types", + "thiserror", + "tokio", + "tracing", + "zstd", +] + [[package]] name = "pbkdf2" version = "0.8.0" @@ -2222,6 +2759,21 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "portable-atomic" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" +dependencies = [ + "portable-atomic 1.6.0", +] + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + [[package]] name = "powerfmt" version = "0.2.0" @@ -2304,6 +2856,27 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2_sqlite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f5d0337e99cd5cacd91ffc326c6cc9d8078def459df560c4f9bf9ba4a51034" +dependencies = [ + "r2d2", + "rusqlite", +] + [[package]] name = "radium" version = "0.7.0" @@ -2454,6 +3027,50 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "relative-path" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" + +[[package]] +name = "reqwest" +version = "0.11.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +dependencies = [ + "base64 0.21.5", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -2490,6 +3107,49 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rstest" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" +dependencies = [ + "cfg-if", + "glob", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.40", + "unicode-ident", +] + +[[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags 1.3.2", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -2582,6 +3242,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "schnorrkel" version = "0.9.1" @@ -2633,6 +3311,29 @@ dependencies = [ "zeroize", ] +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.20" @@ -2681,6 +3382,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_with" version = "2.3.3" @@ -2692,7 +3405,24 @@ dependencies = [ "hex", "serde", "serde_json", - "serde_with_macros", + "serde_with_macros 2.3.3", + "time", +] + +[[package]] +name = "serde_with" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +dependencies = [ + "base64 0.21.5", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.1.0", + "serde", + "serde_json", + "serde_with_macros 3.4.0", "time", ] @@ -2708,6 +3438,18 @@ dependencies = [ "syn 2.0.40", ] +[[package]] +name = "serde_with_macros" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.40", +] + [[package]] name = "sha2" version = "0.8.2" @@ -2790,6 +3532,26 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "sp-arithmetic" version = "16.0.0" @@ -3002,7 +3764,7 @@ dependencies = [ "serde", "serde_json", "serde_json_pythonic", - "serde_with", + "serde_with 2.3.3", "sha3", "starknet-crypto", "starknet-ff", @@ -3058,6 +3820,29 @@ dependencies = [ "serde", ] +[[package]] +name = "starknet-gateway-types" +version = "0.1.0" +source = "git+https://github.com/massalabs/pathfinder.git?rev=b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db#b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" +dependencies = [ + "anyhow", + "fake", + "lazy_static", + "pathfinder-common", + "pathfinder-crypto", + "pathfinder-serde", + "primitive-types", + "rand 0.8.5", + "reqwest", + "rstest", + "serde", + "serde_json", + "serde_with 3.4.0", + "sha3", + "thiserror", + "tokio", +] + [[package]] name = "starknet_api" version = "0.4.1" @@ -3150,6 +3935,27 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -3241,9 +4047,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", + "itoa", + "libc", + "num_threads", "powerfmt", "serde", "time-core", + "time-macros", ] [[package]] @@ -3252,6 +4062,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tiny-bip39" version = "1.0.0" @@ -3271,6 +4090,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -3286,6 +4114,45 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2 0.5.5", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "toml_datetime" version = "0.6.3" @@ -3314,6 +4181,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + [[package]] name = "tracing" version = "0.1.40" @@ -3389,6 +4262,12 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "twox-hash" version = "1.6.3" @@ -3469,12 +4348,29 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vergen" +version = "8.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1290fd64cc4e7d3c9b07d7f333ce0ce0007253e32870e632624835cc80b83939" +dependencies = [ + "anyhow", + "rustversion", + "time", +] + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "w3f-bls" version = "0.1.3" @@ -3499,6 +4395,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -3536,6 +4441,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.89" @@ -3587,7 +4504,7 @@ dependencies = [ "indexmap 1.9.3", "libc", "log", - "object", + "object 0.30.4", "once_cell", "paste", "psm", @@ -3617,10 +4534,10 @@ checksum = "a990198cee4197423045235bf89d3359e69bd2ea031005f4c2d901125955c949" dependencies = [ "anyhow", "cranelift-entity", - "gimli", + "gimli 0.27.3", "indexmap 1.9.3", "log", - "object", + "object 0.30.4", "serde", "target-lexicon", "thiserror", @@ -3634,14 +4551,14 @@ version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0de48df552cfca1c9b750002d3e07b45772dd033b0b206d5c0968496abf31244" dependencies = [ - "addr2line", + "addr2line 0.19.0", "anyhow", "bincode 1.3.3", "cfg-if", "cpp_demangle", - "gimli", + "gimli 0.27.3", "log", - "object", + "object 0.30.4", "rustc-demangle", "serde", "target-lexicon", @@ -3707,6 +4624,16 @@ dependencies = [ "wasmparser", ] +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -3954,6 +4881,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wyz" version = "0.5.1" @@ -4003,6 +4940,25 @@ dependencies = [ "syn 2.0.40", ] +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.9+zstd.1.5.5" diff --git a/Cargo.toml b/Cargo.toml index bb755ae..7e46b15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,12 @@ bitvec = { version = "1", default-features = false } derive_more = { version = "0.99.17", features = ["constructor"] } mp-felt = { git = "https://github.com/keep-starknet-strange/madara.git", rev = "f30acea8af7e28e956e771928130e12bfc084832", package = "mp-felt", features = ["parity-scale-codec", "serde"]} mp-hashers = { git = "https://github.com/keep-starknet-strange/madara.git", rev = "f30acea8af7e28e956e771928130e12bfc084832", package = "mp-hashers" } -mp-transactions = { git = "https://github.com/keep-starknet-strange/madara.git", rev = "f30acea8af7e28e956e771928130e12bfc084832", package = "mp-transactions", features = ["parity-scale-codec", "serde"] } [dev-dependencies] tempfile = "3.8.0" mp-commitments = { git = "https://github.com/keep-starknet-strange/madara.git", rev = "f30acea8af7e28e956e771928130e12bfc084832", package = "mp-commitments" } rand = "0.8.5" +pathfinder-merkle-tree = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-merkle-tree", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } +pathfinder-common = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-common", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } +pathfinder-crypto = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-crypto", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } +pathfinder-storage = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-storage", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } \ No newline at end of file diff --git a/README.md b/README.md index 0052d1b..2c6427f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # bonsai-trie -![example workflow](https://github.com/massalabs/bonsai-trie/actions/workflows/check_lint.yml/badge.svg) ![example workflow](https://github.com/massalabs/bonsai-trie/actions/workflows/test.yml/badge.svg) [![codecov](https://codecov.io/gh/massalabs/bonsai-trie/graph/badge.svg?token=598URC32TV)](https://codecov.io/gh/massalabs/bonsai-trie) - +![example workflow](https://github.com/keep-starknet-strange/bonsai-trie/actions/workflows/check_lint.yml/badge.svg) ![example workflow](https://github.com/keep-starknet-strange/bonsai-trie/actions/workflows/test.yml/badge.svg) [![codecov](https://codecov.io/gh/massalabs/madara-bonsai/branch/main/graph/badge.svg?token=SLIHSUWHT2)](https://codecov.io/gh/massalabs/madara-bonsai) This crate provides a storage implementation based on the Bonsai Storage implemented by [Besu](https://hackmd.io/@kt2am/BktBblIL3). It is a key/value storage that uses a Madara Merkle Trie to store the data. @@ -37,6 +36,7 @@ use bonsai_trie::{ BonsaiStorageError, id::{BasicIdBuilder, BasicId}, BonsaiStorage, BonsaiStorageConfig, BonsaiTrieHash, + ProofNode, Membership }; use mp_felt::Felt252Wrapper; use bitvec::prelude::*; @@ -132,6 +132,18 @@ fn main() { .insert(&BitVec::from_vec(pair4.0.clone()), &pair4.1) .unwrap(); bonsai_storage.commit(id_builder.new_id()).unwrap(); + let proof = bonsai_storage + .get_proof(&BitVec::from_vec(pair3.0.clone())) + .unwrap(); + assert_eq!( + BonsaiStorage::>::verify_proof( + bonsai_storage.root_hash().unwrap(), + &BitVec::from_vec(pair3.0.clone()), + pair3.1, + &proof + ), + Some(Membership::Member) + ); } ``` diff --git a/src/lib.rs b/src/lib.rs index b3a8677..a89f353 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,6 +105,7 @@ pub mod id; pub use bonsai_database::BonsaiDatabase; pub use error::BonsaiStorageError; +pub use trie::merkle_tree::{Membership, ProofNode}; #[cfg(test)] mod tests; @@ -296,6 +297,34 @@ where self.trie.db_mut().commit(id)?; Ok(()) } + + /// Generates a merkle-proof for a given `key`. + /// + /// Returns vector of [`TrieNode`] which form a chain from the root to the key, + /// if it exists, or down to the node which proves that the key does not exist. + /// + /// The nodes are returned in order, root first. + /// + /// Verification is performed by confirming that: + /// 1. the chain follows the path of `key`, and + /// 2. the hashes are correct, and + /// 3. the root hash matches the known root + pub fn get_proof( + &self, + key: &BitSlice, + ) -> Result, BonsaiStorageError> { + self.trie.get_proof(key) + } + + /// Verifies a merkle-proof for a given `key` and `value`. + pub fn verify_proof( + root: Felt252Wrapper, + key: &BitSlice, + value: Felt252Wrapper, + proofs: &[ProofNode], + ) -> Option { + MerkleTree::::verify_proof(root, key, value, proofs) + } } impl BonsaiStorage diff --git a/src/tests/mod.rs b/src/tests/mod.rs index fc9c1c4..0292186 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,4 +1,5 @@ mod madara_comparison; +mod proof; mod simple; mod transactional_state; mod trie_log; diff --git a/src/tests/proof.rs b/src/tests/proof.rs new file mode 100644 index 0000000..48a5dbb --- /dev/null +++ b/src/tests/proof.rs @@ -0,0 +1,309 @@ +use std::collections::HashMap; + +use bitvec::vec::BitVec; +use mp_felt::Felt252Wrapper; +use pathfinder_common::{hash::PedersenHash, trie::TrieNode}; +use pathfinder_crypto::Felt; +use pathfinder_merkle_tree::tree::{MerkleTree, TestStorage}; +use pathfinder_storage::{Node, StoredNode}; +use rand::Rng; + +use crate::{ + databases::{create_rocks_db, RocksDB, RocksDBConfig}, + id::{BasicId, BasicIdBuilder}, + trie::merkle_tree::{Membership, ProofNode}, + BonsaiStorage, BonsaiStorageConfig, +}; + +/// Commits the tree changes and persists them to storage. +fn commit_and_persist( + tree: MerkleTree, + storage: &mut TestStorage, +) -> (Felt, u64) { + use pathfinder_storage::Child; + + for (key, value) in &tree.leaves { + let key = Felt::from_bits(key).unwrap(); + storage.leaves.insert(key, *value); + } + + let update = tree.commit(storage).unwrap(); + + let mut indices = HashMap::new(); + let mut idx = storage.nodes.len(); + for hash in update.nodes.keys() { + indices.insert(*hash, idx as u64); + idx += 1; + } + + for (hash, node) in update.nodes { + let node = match node { + Node::Binary { left, right } => { + let left = match left { + Child::Id(idx) => idx, + Child::Hash(hash) => { + *indices.get(&hash).expect("Left child should have an index") + } + }; + + let right = match right { + Child::Id(idx) => idx, + Child::Hash(hash) => *indices + .get(&hash) + .expect("Right child should have an index"), + }; + + StoredNode::Binary { left, right } + } + Node::Edge { child, path } => { + let child = match child { + Child::Id(idx) => idx, + Child::Hash(hash) => *indices.get(&hash).expect("Child should have an index"), + }; + + StoredNode::Edge { child, path } + } + Node::LeafBinary => StoredNode::LeafBinary, + Node::LeafEdge { path } => StoredNode::LeafEdge { path }, + }; + + storage + .nodes + .insert(*indices.get(&hash).unwrap(), (hash, node)); + } + + let index = *indices.get(&update.root).unwrap(); + + (update.root, index) +} + +fn assert_eq_proof(bonsai_proof: &[ProofNode], pathfinder_proof: &[TrieNode]) { + for (bonsai_node, pathfinder_node) in bonsai_proof.iter().zip(pathfinder_proof.iter()) { + match (bonsai_node, pathfinder_node) { + ( + ProofNode::Binary { left, right }, + pathfinder_common::trie::TrieNode::Binary { + left: pathfinder_left, + right: pathfinder_right, + }, + ) => { + let pathfinder_left_bits = pathfinder_left.to_hex_str(); + let pathfinder_felt = Felt252Wrapper::from_hex_be(&pathfinder_left_bits).unwrap(); + assert_eq!(left, &pathfinder_felt); + let pathfinder_right_bits = pathfinder_right.to_hex_str(); + let pathfinder_felt = Felt252Wrapper::from_hex_be(&pathfinder_right_bits).unwrap(); + assert_eq!(right, &pathfinder_felt); + } + ( + ProofNode::Edge { child, path }, + pathfinder_common::trie::TrieNode::Edge { + child: pathfinder_child, + path: pathfinder_path, + }, + ) => { + let pathfinder_child_bits = pathfinder_child.to_hex_str(); + let pathfinder_felt = Felt252Wrapper::from_hex_be(&pathfinder_child_bits).unwrap(); + assert_eq!(child, &pathfinder_felt); + assert_eq!(&path.0, pathfinder_path); + } + _ => panic!("Proofs are not the same"), + } + } +} + +#[test] +fn basic_proof() { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut storage = pathfinder_merkle_tree::tree::TestStorage::default(); + let mut bonsai_storage = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut pathfinder_merkle_tree: MerkleTree = + pathfinder_merkle_tree::tree::MerkleTree::empty(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 1], + Felt252Wrapper::from_hex_be("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + pathfinder_merkle_tree + .set( + &storage, + bitvec, + Felt::from_hex_str("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap(), + ) + .unwrap(); + let pair2 = ( + vec![1, 2, 2], + Felt252Wrapper::from_hex_be("0x66342762FD54D033c195fec3ce2568b62052e").unwrap(), + ); + let bitvec = BitVec::from_vec(pair2.0.clone()); + bonsai_storage.insert(&bitvec, &pair2.1).unwrap(); + pathfinder_merkle_tree + .set( + &storage, + bitvec, + Felt::from_hex_str("0x66342762FD54D033c195fec3ce2568b62052e").unwrap(), + ) + .unwrap(); + let pair3 = ( + vec![1, 2, 3], + Felt252Wrapper::from_hex_be("0x66342762FD54D033c195fec3ce2568b62052e").unwrap(), + ); + let bitvec = BitVec::from_vec(pair3.0.clone()); + bonsai_storage.insert(&bitvec, &pair3.1).unwrap(); + pathfinder_merkle_tree + .set( + &storage, + bitvec, + Felt::from_hex_str("0x66342762FD54D033c195fec3ce2568b62052e").unwrap(), + ) + .unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + let (_, root_id) = commit_and_persist(pathfinder_merkle_tree.clone(), &mut storage); + let bonsai_proof = bonsai_storage + .get_proof(&BitVec::from_vec(vec![1, 2, 1])) + .unwrap(); + let pathfinder_proof = + pathfinder_merkle_tree::tree::MerkleTree::::get_proof( + root_id, + &storage, + &BitVec::from_vec(vec![1, 2, 1]), + ) + .unwrap(); + assert_eq_proof(&bonsai_proof, &pathfinder_proof); + assert_eq!( + BonsaiStorage::>::verify_proof( + bonsai_storage.root_hash().unwrap(), + &BitVec::from_vec(vec![1, 2, 1]), + pair1.1, + &bonsai_proof + ), + Some(Membership::Member) + ); +} + +#[test] +fn multiple_proofs() { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut storage = pathfinder_merkle_tree::tree::TestStorage::default(); + let mut bonsai_storage = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut pathfinder_merkle_tree: MerkleTree = + pathfinder_merkle_tree::tree::MerkleTree::empty(); + let mut id_builder = BasicIdBuilder::new(); + let mut rng = rand::thread_rng(); + let tree_size = rng.gen_range(10..1000); + let mut elements = vec![]; + for _ in 0..tree_size { + let mut element = String::from("0x"); + let element_size = rng.gen_range(10..32); + for _ in 0..element_size { + let random_byte: u8 = rng.gen(); + element.push_str(&format!("{:02x}", random_byte)); + } + let value = Felt252Wrapper::from_hex_be(&element).unwrap(); + let key = &value.0.to_bytes_be()[..31]; + bonsai_storage + .insert(&BitVec::from_vec(key.to_vec()), &value) + .unwrap(); + pathfinder_merkle_tree + .set( + &storage, + BitVec::from_vec(key.to_vec()), + Felt::from_hex_str(&element).unwrap(), + ) + .unwrap(); + elements.push((key.to_vec(), value)); + } + bonsai_storage.commit(id_builder.new_id()).unwrap(); + let (_, root_id) = commit_and_persist(pathfinder_merkle_tree.clone(), &mut storage); + for element in elements.iter() { + let proof = bonsai_storage + .get_proof(&BitVec::from_vec(element.0.clone())) + .unwrap(); + let pathfinder_proof = + pathfinder_merkle_tree::tree::MerkleTree::::get_proof( + root_id, + &storage, + &BitVec::from_vec(element.0.clone()), + ) + .unwrap(); + assert_eq_proof(&proof, &pathfinder_proof); + assert_eq!( + BonsaiStorage::>::verify_proof( + bonsai_storage.root_hash().unwrap(), + &BitVec::from_vec(element.0.clone()), + element.1, + &proof + ), + Some(Membership::Member) + ); + } +} + +#[test] +fn one_element_proof() { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut storage = pathfinder_merkle_tree::tree::TestStorage::default(); + let mut bonsai_storage = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut pathfinder_merkle_tree: MerkleTree = + pathfinder_merkle_tree::tree::MerkleTree::empty(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 1], + Felt252Wrapper::from_hex_be("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + pathfinder_merkle_tree + .set( + &storage, + bitvec, + Felt::from_hex_str("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap(), + ) + .unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + let (_, root_id) = commit_and_persist(pathfinder_merkle_tree.clone(), &mut storage); + let bonsai_proof = bonsai_storage + .get_proof(&BitVec::from_vec(vec![1, 2, 1])) + .unwrap(); + let pathfinder_proof = + pathfinder_merkle_tree::tree::MerkleTree::::get_proof( + root_id, + &storage, + &BitVec::from_vec(vec![1, 2, 1]), + ) + .unwrap(); + assert_eq_proof(&bonsai_proof, &pathfinder_proof); + assert_eq!( + BonsaiStorage::>::verify_proof( + bonsai_storage.root_hash().unwrap(), + &BitVec::from_vec(vec![1, 2, 1]), + pair1.1, + &bonsai_proof + ), + Some(Membership::Member) + ); +} + +#[test] +fn zero_not_crashing() { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut bonsai_storage = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + bonsai_storage + .get_proof(&BitVec::from_vec(vec![1, 2, 1])) + .unwrap(); +} diff --git a/src/trie/merkle_tree.rs b/src/trie/merkle_tree.rs index 2b6df9f..f506318 100644 --- a/src/trie/merkle_tree.rs +++ b/src/trie/merkle_tree.rs @@ -21,6 +21,12 @@ use super::{ #[cfg(test)] use log::trace; +#[derive(Debug, PartialEq, Eq)] +pub enum Membership { + Member, + NonMember, +} + /// Wrapper type for a [HashMap] object. (It's not really a wrapper it's a /// copy of the type but we implement the necessary traits.) #[derive(Clone, Debug, PartialEq, Eq, Default, Constructor)] @@ -112,6 +118,37 @@ fn test_shared_path_encode_decode() { let decoded = Path::decode(&mut &encoded[..]).unwrap(); assert_eq!(path, decoded); } +/// A node used in proof generated by the trie. +/// +/// Each node hold only the minimum of data that need to be known for the proof: the child hashes (and path for edge node) +#[derive(Debug, Clone, PartialEq)] +pub enum ProofNode { + Binary { + left: Felt252Wrapper, + right: Felt252Wrapper, + }, + Edge { + child: Felt252Wrapper, + path: Path, + }, +} + +impl ProofNode { + pub fn hash(&self) -> Felt252Wrapper { + match self { + ProofNode::Binary { left, right } => Felt252Wrapper(H::hash_elements(left.0, right.0)), + ProofNode::Edge { child, path } => { + let mut bytes = [0u8; 32]; + bytes.view_bits_mut::()[256 - path.0.len()..].copy_from_bitslice(&path.0); + // SAFETY: path len is <= 251 + let path_hash = Felt252Wrapper::try_from(&bytes).unwrap(); + + let length = Felt252Wrapper::from(path.0.len() as u8); + Felt252Wrapper(H::hash_elements(child.0, path_hash.0) + length.0) + } + } + } +} /// A Starknet binary Merkle-Patricia tree with a specific root entry-point and storage. /// @@ -567,8 +604,6 @@ impl MerkleTree { }); let branch_node = node_iter.next(); let parent_branch_node = node_iter.next(); - println!("path: {:?}", last_binary_path); - println!("branch_node: {:?}", branch_node); match branch_node { Some(node_id) => { let new_edge = @@ -576,7 +611,6 @@ impl MerkleTree { let node = self.storage_nodes.0.get_mut(&node_id).ok_or( BonsaiStorageError::Trie("Node not found in memory".to_string()), )?; - println!("node: {:?}", node); let (direction, height) = { // SAFETY: This node must be a binary node due to the iteration condition. let binary = node.as_binary().unwrap(); @@ -704,9 +738,162 @@ impl MerkleTree { self.db.contains(&TrieKeyType::Flat(key.to_vec())) } - /// preload_nodes from the current root towards the destination [Leaf](Node::Leaf) node. - /// Returns the list of nodes along the path. + /// Generates a merkle-proof for a given `key`. + /// + /// if it exists, or down to the node which proves that the key does not exist. + /// + /// The nodes are returned in order, root first. + /// + /// Verification is performed by confirming that: + /// 1. the chain follows the path of `key`, and + /// 2. the hashes are correct, and + /// 3. the root hash matches the known root + /// + /// # Arguments /// + /// * `key` - The key to get the merkle proof of. + /// + /// # Returns + /// + /// The merkle proof and all the child nodes hashes. + pub fn get_proof(&self, key: &BitSlice) -> Result, BonsaiStorageError> + where + BonsaiStorageError: std::convert::From<::DatabaseError>, + { + let mut nodes = Vec::with_capacity(251); + let mut node = match self.root_handle { + NodeHandle::Hash(_) => { + let node = self + .get_tree_branch_in_db_from_path(&BitVec::::new())? + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch root node in db".to_string(), + ))?; + if node.is_empty() { + return Ok(Vec::new()); + } + node + } + NodeHandle::InMemory(root_id) => self + .storage_nodes + .0 + .get(&root_id) + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch root node in the temporary storage".to_string(), + ))? + .clone(), + }; + loop { + match node { + Node::Edge(edge) => { + let child_path = key[..edge.height as usize + edge.path.0.len()].to_bitvec(); + let child_node = match edge.child { + NodeHandle::Hash(hash) => { + let node = self.get_tree_branch_in_db_from_path(&child_path)?; + if let Some(node) = node { + node + } else { + nodes.push(ProofNode::Edge { + child: hash, + path: edge.path.clone(), + }); + return Ok(nodes); + } + } + NodeHandle::InMemory(child_id) => self + .storage_nodes + .0 + .get(&child_id) + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch child node in the temporary storage".to_string(), + ))? + .clone(), + }; + nodes.push(ProofNode::Edge { + child: child_node.hash().ok_or(BonsaiStorageError::Trie( + "Couldn't fetch child node in the temporary storage".to_string(), + ))?, + path: edge.path.clone(), + }); + if edge.path_matches(key) { + node = child_node; + } else { + return Ok(nodes); + } + if edge.common_path(key) == key { + return Ok(nodes); + } + } + Node::Binary(binary) => { + let next_direction = key + .get(binary.height as usize) + .map(|b| Direction::from(*b)) + .ok_or(BonsaiStorageError::Trie("Key too short".to_string()))?; + let next = binary.get_child(next_direction); + let next_path = key[..binary.height as usize + 1].to_bitvec(); + let next_node = match next { + NodeHandle::Hash(_) => self + .get_tree_branch_in_db_from_path(&next_path)? + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch next node in db".to_string(), + ))?, + NodeHandle::InMemory(next_id) => self + .storage_nodes + .0 + .get(&next_id) + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch next node in the temporary storage".to_string(), + ))? + .clone(), + }; + let other = binary.get_child(next_direction.invert()); + let other_hash = match other { + NodeHandle::Hash(hash) => hash, + NodeHandle::InMemory(other_id) => { + let other_node = self + .storage_nodes + .0 + .get(&other_id) + .ok_or(BonsaiStorageError::Trie( + "Couldn't fetch other node in the temporary storage" + .to_string(), + ))? + .clone(); + other_node.hash().ok_or(BonsaiStorageError::Trie( + "Couldn't fetch other node in the temporary storage".to_string(), + ))? + } + }; + match next_direction { + Direction::Left => { + nodes.push(ProofNode::Binary { + left: next_node.hash().ok_or(BonsaiStorageError::Trie( + "Couldn't fetch next node in the temporary storage".to_string(), + ))?, + right: other_hash, + }); + } + Direction::Right => { + nodes.push(ProofNode::Binary { + left: other_hash, + right: next_node.hash().ok_or(BonsaiStorageError::Trie( + "Couldn't fetch next node in the temporary storage".to_string(), + ))?, + }); + } + } + node = next_node; + } + Node::Unresolved(hash) => { + nodes.push(ProofNode::Edge { + child: hash, + path: Path(BitVec::::new()), + }); + return Ok(nodes); + } + } + } + } + /// If the destination node exists, it will be the final node in the list. /// /// This means that the final node will always be either a the destination [Leaf](Node::Leaf) @@ -891,6 +1078,86 @@ impl MerkleTree { Ok(()) } + /// Function that come from pathfinder_merkle_tree::merkle_tree::MerkleTree + /// Verifies that the key `key` with value `value` is indeed part of the MPT that has root + /// `root`, given `proofs`. + /// Supports proofs of non-membership as well as proof of membership: this function returns + /// an enum corresponding to the membership of `value`, or returns `None` in case of a hash mismatch. + /// The algorithm follows this logic: + /// 1. init expected_hash <- root hash + /// 2. loop over nodes: current <- nodes[i] + /// 1. verify the current node's hash matches expected_hash (if not then we have a bad proof) + /// 2. move towards the target - if current is: + /// 1. binary node then choose the child that moves towards the target, else if + /// 2. edge node then check the path against the target bits + /// 1. If it matches then proceed with the child, else + /// 2. if it does not match then we now have a proof that the target does not exist + /// 3. nibble off target bits according to which child you got in (2). If all bits are gone then you + /// have reached the target and the child hash is the value you wanted and the proof is complete. + /// 4. set expected_hash <- to the child hash + /// 3. check that the expected_hash is `value` (we should've reached the leaf) + pub fn verify_proof( + root: Felt252Wrapper, + key: &BitSlice, + value: Felt252Wrapper, + proofs: &[ProofNode], + ) -> Option { + // Protect from ill-formed keys + if key.len() > 251 { + return None; + } + + let mut expected_hash = root; + let mut remaining_path: &BitSlice = key; + + for proof_node in proofs.iter() { + // Hash mismatch? Return None. + if proof_node.hash::() != expected_hash { + return None; + } + match proof_node { + ProofNode::Binary { left, right } => { + // Direction will always correspond to the 0th index + // because we're removing bits on every iteration. + let direction = Direction::from(remaining_path[0]); + + // Set the next hash to be the left or right hash, + // depending on the direction + expected_hash = match direction { + Direction::Left => *left, + Direction::Right => *right, + }; + + // Advance by a single bit + remaining_path = &remaining_path[1..]; + } + ProofNode::Edge { child, path } => { + if path.0 != remaining_path[..path.0.len()] { + // If paths don't match, we've found a proof of non membership because we: + // 1. Correctly moved towards the target insofar as is possible, and + // 2. hashing all the nodes along the path does result in the root hash, which means + // 3. the target definitely does not exist in this tree + return Some(Membership::NonMember); + } + + // Set the next hash to the child's hash + expected_hash = *child; + + // Advance by the whole edge path + remaining_path = &remaining_path[path.0.len()..]; + } + } + } + + // At this point, we should reach `value` ! + if expected_hash == value { + Some(Membership::Member) + } else { + // Hash mismatch. Return `None`. + None + } + } + #[cfg(test)] fn display(&self) { match self.root_handle { @@ -1145,4 +1412,61 @@ mod tests { // let madara_root_hash = madara_tree.commit(); // assert_eq!(bonsai_root_hash, madara_root_hash); // } + + #[test] + fn test_proof() { + let tempdir = tempfile::tempdir().unwrap(); + let rocks_db = create_rocks_db(std::path::Path::new(tempdir.path())).unwrap(); + let rocks_db = RocksDB::new(&rocks_db, RocksDBConfig::default()); + let db = KeyValueDB::new(rocks_db, KeyValueDBConfig::default(), None); + let mut bonsai_tree: super::MerkleTree, BasicId> = + super::MerkleTree::new(db).unwrap(); + let elements = [ + [Felt252Wrapper::from_hex_be("0x665342762FDD54D0303c195fec3ce2568b62052e").unwrap()], + [Felt252Wrapper::from_hex_be("0x66342762FDD54D0303c195fec3ce2568b62052e").unwrap()], + [Felt252Wrapper::from_hex_be("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap()], + ]; + for elem in elements { + elem.iter().for_each(|class_hash| { + let final_hash = + calculate_class_commitment_leaf_hash::(*class_hash); + let key = &class_hash.0.to_bytes_be()[..31]; + bonsai_tree + .set(&BitVec::from_vec(key.to_vec()), final_hash) + .unwrap(); + }); + } + bonsai_tree.commit().unwrap(); + let bonsai_proof = bonsai_tree + .get_proof(&BitVec::from_vec( + elements[0][0].0.to_bytes_be()[..31].to_vec(), + )) + .unwrap(); + println!("bonsai_proof: {:?}", bonsai_proof); + } + + // test in madara + // #[test] + // fn test_proof() { + // let mut tree = super::merkle_patricia_tree::merkle_tree::MerkleTree::::empty(); + // let elements = [ + // [Felt252Wrapper::from_hex_be("0x665342762FDD54D0303c195fec3ce2568b62052e").unwrap()], + // [Felt252Wrapper::from_hex_be("0x66342762FDD54D0303c195fec3ce2568b62052e").unwrap()], + // [Felt252Wrapper::from_hex_be("0x66342762FDD54D033c195fec3ce2568b62052e").unwrap()], + // ]; + // for elem in elements { + // elem.iter().for_each(|class_hash| { + // let final_hash = + // calculate_class_commitment_leaf_hash::(*class_hash); + // let key = &class_hash.0.to_bytes_be()[..31]; + // tree + // .set(&BitVec::from_vec(key.to_vec()), final_hash) + // }); + // } + // tree.commit(); + // let bonsai_proof = tree.get_proof(&BitVec::from_vec( + // elements[0][0].0.to_bytes_be()[..31].to_vec(), + // )); + // println!("bonsai_proof: {:?}", bonsai_proof); + // } }