From 14f1cb933aa812b53be6954e5b7a81ea72e44874 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Wed, 20 Dec 2023 13:25:54 +0100 Subject: [PATCH] chore(primitives): extract trie HashBuilder implementation --- Cargo.lock | 233 ++++--- crates/primitives/Cargo.toml | 2 + .../primitives/src/trie/hash_builder/mod.rs | 644 +----------------- .../src/trie/hash_builder/proof_retainer.rs | 37 - .../primitives/src/trie/hash_builder/state.rs | 58 +- .../primitives/src/trie/hash_builder/value.rs | 71 +- crates/primitives/src/trie/mask.rs | 76 +-- crates/primitives/src/trie/mod.rs | 32 +- crates/primitives/src/trie/nodes/branch.rs | 164 +---- crates/primitives/src/trie/nodes/extension.rs | 53 -- crates/primitives/src/trie/nodes/leaf.rs | 76 --- crates/primitives/src/trie/nodes/mod.rs | 36 +- crates/primitives/src/trie/proofs.rs | 2 + crates/primitives/src/trie/storage.rs | 8 +- crates/primitives/src/trie/subnode.rs | 8 +- .../storage/db/src/tables/codecs/compact.rs | 2 +- crates/storage/db/src/tables/mod.rs | 4 +- crates/trie/src/trie.rs | 2 +- .../trie/src/trie_cursor/database_cursors.rs | 10 +- crates/trie/src/updates.rs | 7 +- crates/trie/src/walker.rs | 4 +- 21 files changed, 263 insertions(+), 1266 deletions(-) delete mode 100644 crates/primitives/src/trie/hash_builder/proof_retainer.rs delete mode 100644 crates/primitives/src/trie/nodes/extension.rs delete mode 100644 crates/primitives/src/trie/nodes/leaf.rs diff --git a/Cargo.lock b/Cargo.lock index dbb474116098..0c7b7a4e6912 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -195,24 +195,25 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" +checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" dependencies = [ "alloy-rlp-derive", "arrayvec", "bytes", + "smol_str", ] [[package]] name = "alloy-rlp-derive" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" +checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -228,7 +229,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "syn-solidity", "tiny-keccak", ] @@ -254,6 +255,25 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-trie" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b13840ded510d1cecf2722a84b8265424d172d4fa5552944ce339a307dc9d6" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "derive_arbitrary", + "derive_more", + "nybbles", + "proptest", + "proptest-derive", + "serde", + "smallvec", + "tracing", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -325,9 +345,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.76" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "aquamarine" @@ -340,7 +360,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -557,18 +577,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -749,7 +769,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.42", + "syn 2.0.41", "which", ] @@ -770,7 +790,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -974,7 +994,7 @@ checksum = "005fa0c5bd20805466dda55eb34cd709bb31a2592bb26927b47714eeed6914d8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "synstructure", ] @@ -1280,7 +1300,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -1314,7 +1334,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -1739,7 +1759,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -1811,7 +1831,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -1844,7 +1864,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -1930,7 +1950,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2104,7 +2124,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2305,7 +2325,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2318,7 +2338,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2329,7 +2349,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2477,7 +2497,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.42", + "syn 2.0.41", "toml 0.8.2", "walkdir", ] @@ -2495,7 +2515,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -2521,7 +2541,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.42", + "syn 2.0.41", "tempfile", "thiserror", "tiny-keccak", @@ -2860,7 +2880,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -3281,9 +3301,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -3296,7 +3316,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.5", + "socket2 0.4.10", "tokio", "tower-service", "tracing", @@ -3350,7 +3370,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.51.1", + "windows-core", ] [[package]] @@ -4122,9 +4142,9 @@ checksum = "3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8" [[package]] name = "mach2" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" dependencies = [ "libc", ] @@ -4183,9 +4203,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "8f850157af41022bbb1b04ed15c011ce4d59520be82a4e3718b10c34b02cb85e" dependencies = [ "libc", ] @@ -4230,20 +4250,20 @@ dependencies = [ [[package]] name = "metrics-macros" -version = "0.7.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b4faf00617defe497754acde3024865bc143d44a86799b24e191ecff91354f" +checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] name = "metrics-process" -version = "1.0.14" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa2a67e2580fbeba4d5a96e659945981e700a383b4cea1432e0cfc18f58c5da" +checksum = "2674a02f6ad51326c2106d9aa5a07d1f759695b655c06df0bba5d5fb338ac0a4" dependencies = [ "libproc", "mach2", @@ -4561,7 +4581,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -4573,7 +4593,7 @@ dependencies = [ "proc-macro-crate 2.0.1", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -4587,9 +4607,9 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836816c354fb2c09622b54545a6f98416147346b13cc7eba5f92fab6b3042c93" +checksum = "47dddada2357f8e7786f4f4d837db7bdddec02c7c3e5da7840d92c70390f6dc0" dependencies = [ "alloy-rlp", "arbitrary", @@ -4897,7 +4917,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -4926,7 +4946,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -4953,9 +4973,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "plain_hasher" @@ -5117,7 +5137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -5180,9 +5200,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -5515,9 +5535,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ "base64 0.21.5", "bytes", @@ -6072,7 +6092,7 @@ dependencies = [ "quote", "regex", "serial_test", - "syn 2.0.42", + "syn 2.0.41", "trybuild", ] @@ -6222,6 +6242,7 @@ version = "0.1.0-alpha.13" dependencies = [ "alloy-primitives", "alloy-rlp", + "alloy-trie", "arbitrary", "assert_matches", "byteorder", @@ -7214,7 +7235,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7241,9 +7262,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" dependencies = [ "serde", ] @@ -7286,7 +7307,7 @@ dependencies = [ "darling 0.20.3", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7311,7 +7332,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7497,6 +7518,15 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + [[package]] name = "snap" version = "1.1.1" @@ -7619,7 +7649,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7667,7 +7697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cccfffbc6bb3bb2d3a26cd2077f4d055f6808d266f9d4d158797a4c60510dfe" dependencies = [ "debugid", - "memmap2 0.9.3", + "memmap2 0.9.1", "stable_deref_trait", "uuid 1.6.1", ] @@ -7696,9 +7726,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.42" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -7714,7 +7744,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7725,7 +7755,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "unicode-xid", ] @@ -7820,7 +7850,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7859,7 +7889,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -7883,9 +7913,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", "itoa", @@ -7905,9 +7935,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -7959,9 +7989,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" dependencies = [ "backtrace", "bytes", @@ -7984,7 +8014,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -8198,7 +8228,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -8372,9 +8402,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "trybuild" -version = "1.0.86" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419ecd263363827c5730386f418715766f584e2f874d32c23c5b00bd9727e7e" +checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" dependencies = [ "basic-toml", "glob", @@ -8663,7 +8693,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "wasm-bindgen-shared", ] @@ -8697,7 +8727,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8794,12 +8824,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.0", + "windows-core", + "windows-targets 0.48.5", ] [[package]] @@ -8811,15 +8841,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -9020,9 +9041,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.30" +version = "0.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" dependencies = [ "memchr", ] @@ -9127,28 +9148,28 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -9168,7 +9189,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", "synstructure", ] @@ -9189,7 +9210,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] @@ -9212,7 +9233,7 @@ checksum = "7a4a1638a1934450809c2266a70362bfc96cd90550c073f5b8a55014d1010157" dependencies = [ "proc-macro2", "quote", - "syn 2.0.42", + "syn 2.0.41", ] [[package]] diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 72e3f5b4b895..288d603bd9fe 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -19,6 +19,7 @@ revm-primitives = { workspace = true, features = ["serde"] } # ethereum alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-rlp = { workspace = true, features = ["arrayvec"] } +alloy-trie = { version = "0.1", features = ["serde"] } ethers-core = { workspace = true, default-features = false, optional = true } nybbles = { version = "0.1", features = ["serde", "rlp"] } @@ -88,6 +89,7 @@ arbitrary = [ "reth-rpc-types/arbitrary", "reth-ethereum-forks/arbitrary", "nybbles/arbitrary", + "alloy-trie/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive", diff --git a/crates/primitives/src/trie/hash_builder/mod.rs b/crates/primitives/src/trie/hash_builder/mod.rs index 6e32d566d8f2..a9bad00a53a2 100644 --- a/crates/primitives/src/trie/hash_builder/mod.rs +++ b/crates/primitives/src/trie/hash_builder/mod.rs @@ -1,647 +1,9 @@ -use super::{ - nodes::{word_rlp, BranchNode, ExtensionNode, LeafNode}, - BranchNodeCompact, Nibbles, TrieMask, -}; -use crate::{constants::EMPTY_ROOT_HASH, keccak256, Bytes, B256}; -use itertools::Itertools; -use std::{ - collections::{BTreeMap, HashMap}, - fmt::Debug, -}; -use tracing::trace; +//! MPT hash builder implementation. mod state; pub use state::HashBuilderState; mod value; -pub use value::HashBuilderValue; +pub(crate) use value::StoredHashBuilderValue; -mod proof_retainer; -pub use proof_retainer::ProofRetainer; - -/// A component used to construct the root hash of the trie. The primary purpose of a Hash Builder -/// is to build the Merkle proof that is essential for verifying the integrity and authenticity of -/// the trie's contents. It achieves this by constructing the root hash from the hashes of child -/// nodes according to specific rules, depending on the type of the node (branch, extension, or -/// leaf). -/// -/// Here's an overview of how the Hash Builder works for each type of node: -/// * Branch Node: The Hash Builder combines the hashes of all the child nodes of the branch node, -/// using a cryptographic hash function like SHA-256. The child nodes' hashes are concatenated -/// and hashed, and the result is considered the hash of the branch node. The process is repeated -/// recursively until the root hash is obtained. -/// * Extension Node: In the case of an extension node, the Hash Builder first encodes the node's -/// shared nibble path, followed by the hash of the next child node. It concatenates these values -/// and then computes the hash of the resulting data, which represents the hash of the extension -/// node. -/// * Leaf Node: For a leaf node, the Hash Builder first encodes the key-path and the value of the -/// leaf node. It then concatenates theĀ encoded key-path and value, and computes the hash of this -/// concatenated data, which represents the hash of the leaf node. -/// -/// The Hash Builder operates recursively, starting from the bottom of the trie and working its way -/// up, combining the hashes of child nodes and ultimately generating the root hash. The root hash -/// can then be used to verify the integrity and authenticity of the trie's data by constructing and -/// verifying Merkle proofs. -#[derive(Debug, Default)] -pub struct HashBuilder { - key: Nibbles, - stack: Vec>, - value: HashBuilderValue, - - groups: Vec, - tree_masks: Vec, - hash_masks: Vec, - - stored_in_database: bool, - - updated_branch_nodes: Option>, - proof_retainer: Option, - - rlp_buf: Vec, -} - -impl From for HashBuilder { - fn from(state: HashBuilderState) -> Self { - Self { - key: Nibbles::from_nibbles_unchecked(state.key), - stack: state.stack, - value: state.value, - groups: state.groups, - tree_masks: state.tree_masks, - hash_masks: state.hash_masks, - stored_in_database: state.stored_in_database, - updated_branch_nodes: None, - proof_retainer: None, - rlp_buf: Vec::with_capacity(32), - } - } -} - -impl From for HashBuilderState { - fn from(state: HashBuilder) -> Self { - Self { - key: state.key.to_vec(), - stack: state.stack, - value: state.value, - groups: state.groups, - tree_masks: state.tree_masks, - hash_masks: state.hash_masks, - stored_in_database: state.stored_in_database, - } - } -} - -impl HashBuilder { - /// Enables the Hash Builder to store updated branch nodes. - /// - /// Call [HashBuilder::split] to get the updates to branch nodes. - pub fn with_updates(mut self, retain_updates: bool) -> Self { - self.set_updates(retain_updates); - self - } - - /// Enable proof retainer for the specified target nibbles. - pub fn with_proof_retainer(mut self, targets: Vec) -> Self { - self.proof_retainer = Some(ProofRetainer::new(targets)); - self - } - - /// Enables the Hash Builder to store updated branch nodes. - /// - /// Call [HashBuilder::split] to get the updates to branch nodes. - pub fn set_updates(&mut self, retain_updates: bool) { - if retain_updates { - self.updated_branch_nodes = Some(HashMap::default()); - } - } - - /// Splits the [HashBuilder] into a [HashBuilder] and hash builder updates. - pub fn split(mut self) -> (Self, HashMap) { - let updates = self.updated_branch_nodes.take(); - (self, updates.unwrap_or_default()) - } - - /// Take and return the proofs retained. - pub fn take_proofs(&mut self) -> BTreeMap { - self.proof_retainer.take().map(ProofRetainer::into_proofs).unwrap_or_default() - } - - /// The number of total updates accrued. - /// Returns `0` if [Self::with_updates] was not called. - pub fn updates_len(&self) -> usize { - self.updated_branch_nodes.as_ref().map(|u| u.len()).unwrap_or(0) - } - - /// Print the current stack of the Hash Builder. - pub fn print_stack(&self) { - println!("============ STACK ==============="); - for item in &self.stack { - println!("{}", crate::hex::encode(item)); - } - println!("============ END STACK ==============="); - } - - /// Adds a new leaf element & its value to the trie hash builder. - pub fn add_leaf(&mut self, key: Nibbles, value: &[u8]) { - assert!(key > self.key); - if !self.key.is_empty() { - self.update(&key); - } - self.set_key_value(key, value); - } - - /// Adds a new branch element & its hash to the trie hash builder. - pub fn add_branch(&mut self, key: Nibbles, value: B256, stored_in_database: bool) { - assert!(key > self.key || (self.key.is_empty() && key.is_empty())); - if !self.key.is_empty() { - self.update(&key); - } else if key.is_empty() { - self.stack.push(word_rlp(&value)); - } - self.set_key_value(key, value); - self.stored_in_database = stored_in_database; - } - - /// Returns the current root hash of the trie builder. - pub fn root(&mut self) -> B256 { - // Clears the internal state - if !self.key.is_empty() { - self.update(&Nibbles::default()); - self.key.clear(); - self.value = HashBuilderValue::Bytes(vec![]); - } - self.current_root() - } - - fn set_key_value>(&mut self, key: Nibbles, value: T) { - trace!(target: "trie::hash_builder", key = ?self.key, value = ?self.value, "old key/value"); - self.key = key; - self.value = value.into(); - trace!(target: "trie::hash_builder", key = ?self.key, value = ?self.value, "new key/value"); - } - - fn current_root(&self) -> B256 { - if let Some(node_ref) = self.stack.last() { - if node_ref.len() == B256::len_bytes() + 1 { - B256::from_slice(&node_ref[1..]) - } else { - keccak256(node_ref) - } - } else { - EMPTY_ROOT_HASH - } - } - - /// Given a new element, it appends it to the stack and proceeds to loop through the stack state - /// and convert the nodes it can into branch / extension nodes and hash them. This ensures - /// that the top of the stack always contains the merkle root corresponding to the trie - /// built so far. - fn update(&mut self, succeeding: &Nibbles) { - let mut build_extensions = false; - // current / self.key is always the latest added element in the trie - let mut current = self.key.clone(); - - trace!(target: "trie::hash_builder", ?current, ?succeeding, "updating merkle tree"); - - let mut i = 0usize; - let span = tracing::trace_span!( - target: "trie::hash_builder", - "loop", - i = tracing::field::Empty, - current = tracing::field::Empty, - build_extensions = tracing::field::Empty, - ) - .entered(); - loop { - if !span.is_disabled() { - span.record("i", i); - span.record("current", &format!("{current:?}")); - span.record("build_extensions", build_extensions); - } - - let preceding_exists = !self.groups.is_empty(); - let preceding_len = self.groups.len().saturating_sub(1); - - let common_prefix_len = succeeding.common_prefix_length(current.as_slice()); - let len = std::cmp::max(preceding_len, common_prefix_len); - assert!(len < current.len()); - - trace!( - target: "trie::hash_builder", - ?len, - ?common_prefix_len, - ?preceding_len, - preceding_exists, - "prefix lengths after comparing keys" - ); - - // Adjust the state masks for branch calculation - let extra_digit = current[len]; - if self.groups.len() <= len { - let new_len = len + 1; - trace!(target: "trie::hash_builder", new_len, old_len = self.groups.len(), "scaling state masks to fit"); - self.groups.resize(new_len, TrieMask::default()); - } - self.groups[len] |= TrieMask::from_nibble(extra_digit); - trace!( - target: "trie::hash_builder", - ?extra_digit, - groups = ?self.groups.iter().format(", "), - ); - - // Adjust the tree masks for exporting to the DB - if self.tree_masks.len() < current.len() { - self.resize_masks(current.len()); - } - - let mut len_from = len; - if !succeeding.is_empty() || preceding_exists { - len_from += 1; - } - trace!(target: "trie::hash_builder", "skipping {len_from} nibbles"); - - // The key without the common prefix - let short_node_key = current.slice(len_from..); - trace!(target: "trie::hash_builder", ?short_node_key); - - // Concatenate the 2 nodes together - if !build_extensions { - match &self.value { - HashBuilderValue::Bytes(leaf_value) => { - let leaf_node = LeafNode::new(&short_node_key, leaf_value); - trace!(target: "trie::hash_builder", ?leaf_node, "pushing leaf node"); - trace!(target: "trie::hash_builder", rlp = { - self.rlp_buf.clear(); - crate::hex::encode(&leaf_node.rlp(&mut self.rlp_buf)) - }, "leaf node rlp"); - - self.rlp_buf.clear(); - self.stack.push(leaf_node.rlp(&mut self.rlp_buf)); - self.retain_proof_from_buf(¤t); - } - HashBuilderValue::Hash(hash) => { - trace!(target: "trie::hash_builder", ?hash, "pushing branch node hash"); - self.stack.push(word_rlp(hash)); - - if self.stored_in_database { - self.tree_masks[current.len() - 1] |= - TrieMask::from_nibble(current.last().unwrap()); - } - self.hash_masks[current.len() - 1] |= - TrieMask::from_nibble(current.last().unwrap()); - - build_extensions = true; - } - } - } - - if build_extensions && !short_node_key.is_empty() { - self.update_masks(¤t, len_from); - let stack_last = - self.stack.pop().expect("there should be at least one stack item; qed"); - let extension_node = ExtensionNode::new(&short_node_key, &stack_last); - trace!(target: "trie::hash_builder", ?extension_node, "pushing extension node"); - trace!(target: "trie::hash_builder", rlp = { - self.rlp_buf.clear(); - crate::hex::encode(&extension_node.rlp(&mut self.rlp_buf)) - }, "extension node rlp"); - self.rlp_buf.clear(); - self.stack.push(extension_node.rlp(&mut self.rlp_buf)); - self.retain_proof_from_buf(¤t.slice(..len_from)); - self.resize_masks(len_from); - } - - if preceding_len <= common_prefix_len && !succeeding.is_empty() { - trace!(target: "trie::hash_builder", "no common prefix to create branch nodes from, returning"); - return - } - - // Insert branch nodes in the stack - if !succeeding.is_empty() || preceding_exists { - // Pushes the corresponding branch node to the stack - let children = self.push_branch_node(¤t, len); - // Need to store the branch node in an efficient format - // outside of the hash builder - self.store_branch_node(¤t, len, children); - } - - self.groups.resize(len, TrieMask::default()); - self.resize_masks(len); - - if preceding_len == 0 { - trace!(target: "trie::hash_builder", "0 or 1 state masks means we have no more elements to process"); - return - } - - current.truncate(preceding_len); - trace!(target: "trie::hash_builder", ?current, "truncated nibbles to {} bytes", preceding_len); - - trace!(target: "trie::hash_builder", groups = ?self.groups, "popping empty state masks"); - while self.groups.last() == Some(&TrieMask::default()) { - self.groups.pop(); - } - - build_extensions = true; - - i += 1; - } - } - - /// Given the size of the longest common prefix, it proceeds to create a branch node - /// from the state mask and existing stack state, and store its RLP to the top of the stack, - /// after popping all the relevant elements from the stack. - fn push_branch_node(&mut self, current: &Nibbles, len: usize) -> Vec { - let state_mask = self.groups[len]; - let hash_mask = self.hash_masks[len]; - let branch_node = BranchNode::new(&self.stack); - let children = branch_node.children(state_mask, hash_mask).collect(); - - self.rlp_buf.clear(); - let rlp = branch_node.rlp(state_mask, &mut self.rlp_buf); - self.retain_proof_from_buf(¤t.slice(..len)); - - // Clears the stack from the branch node elements - let first_child_idx = self.stack.len() - state_mask.count_ones() as usize; - trace!( - target: "trie::hash_builder", - new_len = first_child_idx, - old_len = self.stack.len(), - "resizing stack to prepare branch node" - ); - self.stack.resize(first_child_idx, vec![]); - - trace!(target: "trie::hash_builder", "pushing branch node with {:?} mask from stack", state_mask); - trace!(target: "trie::hash_builder", rlp = crate::hex::encode(&rlp), "branch node rlp"); - self.stack.push(rlp); - children - } - - /// Given the current nibble prefix and the highest common prefix length, proceeds - /// to update the masks for the next level and store the branch node and the - /// masks in the database. We will use that when consuming the intermediate nodes - /// from the database to efficiently build the trie. - fn store_branch_node(&mut self, current: &Nibbles, len: usize, children: Vec) { - if len > 0 { - let parent_index = len - 1; - self.hash_masks[parent_index] |= TrieMask::from_nibble(current[parent_index]); - } - - let store_in_db_trie = !self.tree_masks[len].is_empty() || !self.hash_masks[len].is_empty(); - if store_in_db_trie { - if len > 0 { - let parent_index = len - 1; - self.tree_masks[parent_index] |= TrieMask::from_nibble(current[parent_index]); - } - - let mut n = BranchNodeCompact::new( - self.groups[len], - self.tree_masks[len], - self.hash_masks[len], - children, - None, - ); - - if len == 0 { - n.root_hash = Some(self.current_root()); - } - - // Send it over to the provided channel which will handle it on the - // other side of the HashBuilder - trace!(target: "trie::hash_builder", node = ?n, "intermediate node"); - let common_prefix = current.slice(..len); - if let Some(nodes) = self.updated_branch_nodes.as_mut() { - nodes.insert(common_prefix, n); - } - } - } - - fn retain_proof_from_buf(&mut self, prefix: &Nibbles) { - if let Some(proof_retainer) = self.proof_retainer.as_mut() { - proof_retainer.retain(prefix, &self.rlp_buf) - } - } - - fn update_masks(&mut self, current: &Nibbles, len_from: usize) { - if len_from > 0 { - let flag = TrieMask::from_nibble(current[len_from - 1]); - - self.hash_masks[len_from - 1] &= !flag; - - if !self.tree_masks[current.len() - 1].is_empty() { - self.tree_masks[len_from - 1] |= flag; - } - } - } - - fn resize_masks(&mut self, new_len: usize) { - trace!( - target: "trie::hash_builder", - new_len, - old_tree_mask_len = self.tree_masks.len(), - old_hash_mask_len = self.hash_masks.len(), - "resizing tree/hash masks" - ); - self.tree_masks.resize(new_len, TrieMask::default()); - self.hash_masks.resize(new_len, TrieMask::default()); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{hex_literal::hex, proofs::triehash::KeccakHasher, B256, U256}; - use proptest::prelude::*; - use std::collections::{BTreeMap, HashMap}; - - fn trie_root(iter: I) -> B256 - where - I: IntoIterator, - K: AsRef<[u8]> + Ord, - V: AsRef<[u8]>, - { - // We use `trie_root` instead of `sec_trie_root` because we assume - // the incoming keys are already hashed, which makes sense given - // we're going to be using the Hashed tables & pre-hash the data - // on the way in. - triehash::trie_root::(iter) - } - - // Hashes the keys, RLP encodes the values, compares the trie builder with the upstream root. - fn assert_hashed_trie_root<'a, I, K>(iter: I) - where - I: Iterator, - K: AsRef<[u8]> + Ord, - { - let hashed = iter - .map(|(k, v)| (keccak256(k.as_ref()), alloy_rlp::encode_fixed_size(v).to_vec())) - // Collect into a btree map to sort the data - .collect::>(); - - let mut hb = HashBuilder::default(); - - hashed.iter().for_each(|(key, val)| { - let nibbles = Nibbles::unpack(key); - hb.add_leaf(nibbles, val); - }); - - assert_eq!(hb.root(), trie_root(&hashed)); - } - - // No hashing involved - fn assert_trie_root(iter: I) - where - I: Iterator, - K: AsRef<[u8]> + Ord, - V: AsRef<[u8]>, - { - let mut hb = HashBuilder::default(); - - let data = iter.collect::>(); - data.iter().for_each(|(key, val)| { - let nibbles = Nibbles::unpack(key); - hb.add_leaf(nibbles, val.as_ref()); - }); - assert_eq!(hb.root(), trie_root(data)); - } - - #[test] - fn empty() { - assert_eq!(HashBuilder::default().root(), EMPTY_ROOT_HASH); - } - - #[test] - fn arbitrary_hashed_root() { - proptest!(|(state: BTreeMap)| { - assert_hashed_trie_root(state.iter()); - }); - } - - #[test] - fn test_generates_branch_node() { - let mut hb = HashBuilder::default().with_updates(true); - - // We have 1 branch node update to be stored at 0x01, indicated by the first nibble. - // That branch root node has 2 branch node children present at 0x1 and 0x2. - // - 0x1 branch: It has the 2 empty items, at `0` and `1`. - // - 0x2 branch: It has the 2 empty items, at `0` and `2`. - // This is enough information to construct the intermediate node value: - // 1. State Mask: 0b111. The children of the branch + the branch value at `0`, `1` and `2`. - // 2. Hash Mask: 0b110. Of the above items, `1` and `2` correspond to sub-branch nodes. - // 3. Tree Mask: 0b000. - // 4. Hashes: The 2 sub-branch roots, at `1` and `2`, calculated by hashing - // the 0th and 1st element for the 0x1 branch (according to the 3rd nibble), - // and the 0th and 2nd element for the 0x2 branch (according to the 3rd nibble). - // This basically means that every BranchNodeCompact is capable of storing up to 2 levels - // deep of nodes (?). - let data = BTreeMap::from([ - ( - hex!("1000000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ( - hex!("1100000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ( - hex!("1110000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ( - hex!("1200000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ( - hex!("1220000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ( - // unrelated leaf - hex!("1320000000000000000000000000000000000000000000000000000000000000").to_vec(), - Vec::new(), - ), - ]); - data.iter().for_each(|(key, val)| { - let nibbles = Nibbles::unpack(key); - hb.add_leaf(nibbles, val.as_ref()); - }); - let root = hb.root(); - - let (_, updates) = hb.split(); - - let update = updates.get(&Nibbles::from_nibbles_unchecked(hex!("01"))).unwrap(); - assert_eq!(update.state_mask, TrieMask::new(0b1111)); // 1st nibble: 0, 1, 2, 3 - assert_eq!(update.tree_mask, TrieMask::new(0)); - assert_eq!(update.hash_mask, TrieMask::new(6)); // in the 1st nibble, the ones with 1 and 2 are branches with `hashes` - assert_eq!(update.hashes.len(), 2); // calculated while the builder is running - - assert_eq!(root, trie_root(data)); - } - - #[test] - fn test_root_raw_data() { - let data = vec![ - (hex!("646f").to_vec(), hex!("76657262").to_vec()), - (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()), - (hex!("676f6b32").to_vec(), hex!("7075707079").to_vec()), - (hex!("676f6b34").to_vec(), hex!("7075707079").to_vec()), - ]; - assert_trie_root(data.into_iter()); - } - - #[test] - fn test_root_rlp_hashed_data() { - let data = HashMap::from([ - (B256::with_last_byte(1), U256::from(2)), - (B256::with_last_byte(3), U256::from(4)), - ]); - assert_hashed_trie_root(data.iter()); - } - - #[test] - fn test_root_known_hash() { - let root_hash = B256::random(); - let mut hb = HashBuilder::default(); - hb.add_branch(Nibbles::default(), root_hash, false); - assert_eq!(hb.root(), root_hash); - } - - #[test] - fn manual_branch_node_ok() { - let raw_input = vec![ - (hex!("646f").to_vec(), hex!("76657262").to_vec()), - (hex!("676f6f64").to_vec(), hex!("7075707079").to_vec()), - ]; - let input = - raw_input.iter().map(|(key, value)| (Nibbles::unpack(key), value)).collect::>(); - - // We create the hash builder and add the leaves - let mut hb = HashBuilder::default(); - for (key, val) in input.iter() { - hb.add_leaf(key.clone(), val.as_slice()); - } - - // Manually create the branch node that should be there after the first 2 leaves are added. - // Skip the 0th element given in this example they have a common prefix and will - // collapse to a Branch node. - use crate::bytes::BytesMut; - use alloy_rlp::Encodable; - let leaf1 = LeafNode::new(&Nibbles::unpack(&raw_input[0].0[1..]), input[0].1); - let leaf2 = LeafNode::new(&Nibbles::unpack(&raw_input[1].0[1..]), input[1].1); - let mut branch: [&dyn Encodable; 17] = [b""; 17]; - // We set this to `4` and `7` because that mathces the 2nd element of the corresponding - // leaves. We set this to `7` because the 2nd element of Leaf 1 is `7`. - branch[4] = &leaf1; - branch[7] = &leaf2; - let mut branch_node_rlp = BytesMut::new(); - alloy_rlp::encode_list::<_, dyn Encodable>(&branch, &mut branch_node_rlp); - let branch_node_hash = keccak256(branch_node_rlp); - - let mut hb2 = HashBuilder::default(); - // Insert the branch with the `0x6` shared prefix. - hb2.add_branch(Nibbles::from_nibbles_unchecked([0x6]), branch_node_hash, false); - - let expected = trie_root(raw_input.clone()); - assert_eq!(hb.root(), expected); - assert_eq!(hb2.root(), expected); - } -} +pub use alloy_trie::hash_builder::*; diff --git a/crates/primitives/src/trie/hash_builder/proof_retainer.rs b/crates/primitives/src/trie/hash_builder/proof_retainer.rs deleted file mode 100644 index 04c23a929b6b..000000000000 --- a/crates/primitives/src/trie/hash_builder/proof_retainer.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{trie::Nibbles, Bytes}; -use std::collections::BTreeMap; - -/// Proof retainer is used to store proofs during merkle trie construction. -/// It is intended to be used within the [`HashBuilder`](crate::trie::HashBuilder). -#[derive(Debug)] -pub struct ProofRetainer { - /// The nibbles of the target trie keys to retain proofs for. - targets: Vec, - /// The map of retained proofs (RLP serialized trie nodes) - /// with their corresponding key in the trie. - proofs: BTreeMap, -} - -impl ProofRetainer { - /// Create new retainer with target nibbles. - pub fn new(targets: Vec) -> Self { - Self { targets, proofs: Default::default() } - } - - /// Returns `true` if the given prefix matches the retainer target. - pub fn matches(&self, prefix: &Nibbles) -> bool { - self.targets.iter().any(|target| target.starts_with(prefix)) - } - - /// Returns all collected proofs. - pub fn into_proofs(self) -> BTreeMap { - self.proofs - } - - /// Retain the proof if the key matches any of the targets. - pub fn retain(&mut self, prefix: &Nibbles, proof: &[u8]) { - if self.matches(prefix) { - self.proofs.insert(prefix.clone(), Bytes::from(proof.to_vec())); - } - } -} diff --git a/crates/primitives/src/trie/hash_builder/state.rs b/crates/primitives/src/trie/hash_builder/state.rs index c714dedd0bb4..5bf768e38d97 100644 --- a/crates/primitives/src/trie/hash_builder/state.rs +++ b/crates/primitives/src/trie/hash_builder/state.rs @@ -1,5 +1,8 @@ -use super::{super::TrieMask, HashBuilderValue}; +use super::StoredHashBuilderValue; +use crate::trie::{StoredTrieMask, TrieMask}; +use alloy_trie::{hash_builder::HashBuilderValue, HashBuilder}; use bytes::Buf; +use nybbles::Nibbles; use reth_codecs::{derive_arbitrary, Compact}; use serde::{Deserialize, Serialize}; @@ -26,6 +29,37 @@ pub struct HashBuilderState { pub stored_in_database: bool, } +impl From for HashBuilder { + fn from(state: HashBuilderState) -> Self { + Self { + key: Nibbles::from_nibbles_unchecked(state.key), + stack: state.stack, + value: state.value, + groups: state.groups, + tree_masks: state.tree_masks, + hash_masks: state.hash_masks, + stored_in_database: state.stored_in_database, + updated_branch_nodes: None, + proof_retainer: None, + rlp_buf: Vec::with_capacity(32), + } + } +} + +impl From for HashBuilderState { + fn from(state: HashBuilder) -> Self { + Self { + key: state.key.into(), + stack: state.stack, + value: state.value, + groups: state.groups, + tree_masks: state.tree_masks, + hash_masks: state.hash_masks, + stored_in_database: state.stored_in_database, + } + } +} + impl Compact for HashBuilderState { fn to_compact(self, buf: &mut B) -> usize where @@ -43,24 +77,24 @@ impl Compact for HashBuilderState { len += 2 + item.len(); } - len += self.value.to_compact(buf); + len += StoredHashBuilderValue(self.value).to_compact(buf); buf.put_u16(self.groups.len() as u16); len += 2; - for item in self.groups.iter() { - len += item.to_compact(buf); + for item in &self.groups { + len += StoredTrieMask(*item).to_compact(buf); } buf.put_u16(self.tree_masks.len() as u16); len += 2; - for item in self.tree_masks.iter() { - len += item.to_compact(buf); + for item in &self.tree_masks { + len += StoredTrieMask(*item).to_compact(buf); } buf.put_u16(self.hash_masks.len() as u16); len += 2; - for item in self.hash_masks.iter() { - len += item.to_compact(buf); + for item in &self.hash_masks { + len += StoredTrieMask(*item).to_compact(buf); } buf.put_u8(self.stored_in_database as u8); @@ -79,12 +113,12 @@ impl Compact for HashBuilderState { buf.advance(item_len); } - let (value, mut buf) = HashBuilderValue::from_compact(buf, 0); + let (StoredHashBuilderValue(value), mut buf) = StoredHashBuilderValue::from_compact(buf, 0); let groups_len = buf.get_u16() as usize; let mut groups = Vec::with_capacity(groups_len); for _ in 0..groups_len { - let (item, rest) = TrieMask::from_compact(buf, 0); + let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0); groups.push(item); buf = rest; } @@ -92,7 +126,7 @@ impl Compact for HashBuilderState { let tree_masks_len = buf.get_u16() as usize; let mut tree_masks = Vec::with_capacity(tree_masks_len); for _ in 0..tree_masks_len { - let (item, rest) = TrieMask::from_compact(buf, 0); + let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0); tree_masks.push(item); buf = rest; } @@ -100,7 +134,7 @@ impl Compact for HashBuilderState { let hash_masks_len = buf.get_u16() as usize; let mut hash_masks = Vec::with_capacity(hash_masks_len); for _ in 0..hash_masks_len { - let (item, rest) = TrieMask::from_compact(buf, 0); + let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0); hash_masks.push(item); buf = rest; } diff --git a/crates/primitives/src/trie/hash_builder/value.rs b/crates/primitives/src/trie/hash_builder/value.rs index fed85e680cf9..a829f85175e8 100644 --- a/crates/primitives/src/trie/hash_builder/value.rs +++ b/crates/primitives/src/trie/hash_builder/value.rs @@ -1,78 +1,39 @@ -use crate::B256; -use reth_codecs::{derive_arbitrary, Compact}; -use serde::{Deserialize, Serialize}; +use alloy_primitives::B256; +use alloy_trie::hash_builder::HashBuilderValue; +use bytes::Buf; +use reth_codecs::Compact; -/// The current value of the hash builder. -#[derive_arbitrary(compact)] -#[derive(Clone, PartialEq, Serialize, Deserialize)] -pub enum HashBuilderValue { - /// Value of the leaf node. - Hash(B256), - /// Hash of adjacent nodes. - Bytes(Vec), -} +/// A wrapper around `HashBuilderValue` that implements `Compact`. +pub(crate) struct StoredHashBuilderValue(pub(crate) HashBuilderValue); -impl Compact for HashBuilderValue { +impl Compact for StoredHashBuilderValue { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, { - match self { - Self::Hash(hash) => { + match self.0 { + HashBuilderValue::Hash(hash) => { buf.put_u8(0); 1 + hash.to_compact(buf) } - Self::Bytes(bytes) => { + HashBuilderValue::Bytes(bytes) => { buf.put_u8(1); 1 + bytes.to_compact(buf) } } } - fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) { - match buf[0] { + fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) { + match buf.get_u8() { 0 => { - let (hash, buf) = B256::from_compact(&buf[1..], 32); - (Self::Hash(hash), buf) + let (hash, buf) = B256::from_compact(buf, 32); + (Self(HashBuilderValue::Hash(hash)), buf) } 1 => { - let (bytes, buf) = Vec::from_compact(&buf[1..], 0); - (Self::Bytes(bytes), buf) + let (bytes, buf) = Vec::from_compact(buf, 0); + (Self(HashBuilderValue::Bytes(bytes)), buf) } _ => unreachable!("Junk data in database: unknown HashBuilderValue variant"), } } } - -impl std::fmt::Debug for HashBuilderValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Bytes(bytes) => write!(f, "Bytes({:?})", crate::hex::encode(bytes)), - Self::Hash(hash) => write!(f, "Hash({:?})", hash), - } - } -} - -impl From> for HashBuilderValue { - fn from(value: Vec) -> Self { - Self::Bytes(value) - } -} - -impl From<&[u8]> for HashBuilderValue { - fn from(value: &[u8]) -> Self { - Self::Bytes(value.to_vec()) - } -} - -impl From for HashBuilderValue { - fn from(value: B256) -> Self { - Self::Hash(value) - } -} - -impl Default for HashBuilderValue { - fn default() -> Self { - Self::Bytes(vec![]) - } -} diff --git a/crates/primitives/src/trie/mask.rs b/crates/primitives/src/trie/mask.rs index 16fdd69597b9..02c74d2cc071 100644 --- a/crates/primitives/src/trie/mask.rs +++ b/crates/primitives/src/trie/mask.rs @@ -1,84 +1,20 @@ +use super::TrieMask; use bytes::Buf; -use derive_more::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Deref, From, Not}; -use reth_codecs::{derive_arbitrary, Compact}; -use serde::{Deserialize, Serialize}; +use reth_codecs::Compact; -/// A struct representing a mask of 16 bits, used for Ethereum trie operations. -/// -/// Masks in a trie are used to efficiently represent and manage information about the presence or -/// absence of certain elements, such as child nodes, within a trie. Masks are usually implemented -/// as bit vectors, where each bit represents the presence (1) or absence (0) of a corresponding -/// element. -#[derive( - Default, - Clone, - Copy, - PartialEq, - Eq, - Serialize, - Deserialize, - PartialOrd, - Ord, - Deref, - From, - BitAnd, - BitAndAssign, - BitOr, - BitOrAssign, - Not, -)] -#[derive_arbitrary(compact)] -pub struct TrieMask(u16); +pub(crate) struct StoredTrieMask(pub(crate) TrieMask); -impl TrieMask { - /// Creates a new `TrieMask` from the given inner value. - #[inline] - pub fn new(inner: u16) -> Self { - Self(inner) - } - - /// Creates a new `TrieMask` from the given nibble. - #[inline] - pub fn from_nibble(nibble: u8) -> Self { - Self(1u16 << nibble) - } - - /// Returns `true` if the current `TrieMask` is a subset of `other`. - #[inline] - pub fn is_subset_of(self, other: Self) -> bool { - self & other == self - } - - /// Returns `true` if a given bit is set in a mask. - #[inline] - pub fn is_bit_set(self, index: u8) -> bool { - self.0 & (1u16 << index) != 0 - } - - /// Returns `true` if the mask is empty. - #[inline] - pub fn is_empty(self) -> bool { - self.0 == 0 - } -} - -impl std::fmt::Debug for TrieMask { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "TrieMask({:016b})", self.0) - } -} - -impl Compact for TrieMask { +impl Compact for StoredTrieMask { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, { - buf.put_u16(self.0); + buf.put_u16(self.0.get()); 2 } fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) { let mask = buf.get_u16(); - (Self(mask), buf) + (Self(TrieMask::new(mask)), buf) } } diff --git a/crates/primitives/src/trie/mod.rs b/crates/primitives/src/trie/mod.rs index 0081678ac463..848aaed646f4 100644 --- a/crates/primitives/src/trie/mod.rs +++ b/crates/primitives/src/trie/mod.rs @@ -1,27 +1,27 @@ //! Collection of trie related types. -/// Various branch nodes produced by the hash builder. -pub mod nodes; -pub use nodes::BranchNodeCompact; - /// The implementation of hash builder. pub mod hash_builder; -pub use hash_builder::HashBuilder; - -/// Merkle trie proofs. -mod proofs; -pub use proofs::{AccountProof, StorageProof}; mod account; +pub use account::TrieAccount; + mod mask; +pub(crate) use mask::StoredTrieMask; + mod nibbles; +pub use nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey}; + +pub mod nodes; +pub use nodes::StoredBranchNode; + +mod proofs; +pub use proofs::{AccountProof, StorageProof}; + mod storage; +pub use storage::StorageTrieEntry; + mod subnode; +pub use subnode::StoredSubNode; -pub use self::{ - account::TrieAccount, - mask::TrieMask, - nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey}, - storage::StorageTrieEntry, - subnode::StoredSubNode, -}; +pub use alloy_trie::{BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH}; diff --git a/crates/primitives/src/trie/nodes/branch.rs b/crates/primitives/src/trie/nodes/branch.rs index 961050be3f8d..45182d081935 100644 --- a/crates/primitives/src/trie/nodes/branch.rs +++ b/crates/primitives/src/trie/nodes/branch.rs @@ -1,154 +1,26 @@ -use super::{super::TrieMask, rlp_node, CHILD_INDEX_RANGE}; -use crate::B256; -use alloy_rlp::{BufMut, EMPTY_STRING_CODE}; +use crate::trie::StoredTrieMask; +use alloy_primitives::B256; +use alloy_trie::BranchNodeCompact; use bytes::Buf; use reth_codecs::Compact; use serde::{Deserialize, Serialize}; -/// A Branch node is only a pointer to the stack of nodes and is used to -/// create the RLP encoding of the node using masks which filter from -/// the stack of nodes. -#[derive(Clone, Debug)] -pub struct BranchNode<'a> { - /// Rlp encoded children - pub stack: &'a [Vec], -} - -impl<'a> BranchNode<'a> { - /// Create a new branch node from the stack of nodes. - pub fn new(stack: &'a [Vec]) -> Self { - Self { stack } - } - - /// Given the hash and state mask of children present, return an iterator over the stack items - /// that match the mask. - pub fn children( - &self, - state_mask: TrieMask, - hash_mask: TrieMask, - ) -> impl Iterator + '_ { - let mut index = self.stack.len() - state_mask.count_ones() as usize; - CHILD_INDEX_RANGE.filter_map(move |digit| { - let mut child = None; - if state_mask.is_bit_set(digit) { - if hash_mask.is_bit_set(digit) { - child = Some(&self.stack[index]); - } - index += 1; - } - child.map(|child| B256::from_slice(&child[1..])) - }) - } - - /// Returns the RLP encoding of the branch node given the state mask of children present. - pub fn rlp(&self, state_mask: TrieMask, buf: &mut Vec) -> Vec { - let first_child_idx = self.stack.len() - state_mask.count_ones() as usize; - - // Create the RLP header from the mask elements present. - let mut i = first_child_idx; - let header = CHILD_INDEX_RANGE.fold( - alloy_rlp::Header { list: true, payload_length: 1 }, - |mut header, digit| { - if state_mask.is_bit_set(digit) { - header.payload_length += self.stack[i].len(); - i += 1; - } else { - header.payload_length += 1; - } - header - }, - ); - header.encode(buf); - - // Extend the RLP buffer with the present children - let mut i = first_child_idx; - CHILD_INDEX_RANGE.for_each(|idx| { - if state_mask.is_bit_set(idx) { - buf.extend_from_slice(&self.stack[i]); - i += 1; - } else { - buf.put_u8(EMPTY_STRING_CODE) - } - }); - - // Is this needed? - buf.put_u8(EMPTY_STRING_CODE); - - rlp_node(buf) - } -} - -/// A struct representing a branch node in an Ethereum trie. -/// -/// A branch node can have up to 16 children, each corresponding to one of the possible nibble -/// values (0 to 15) in the trie's path. -/// -/// The masks in a BranchNode are used to efficiently represent and manage information about the -/// presence and types of its children. They are bitmasks, where each bit corresponds to a nibble -/// (half-byte, or 4 bits) value from 0 to 15. -#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] -pub struct BranchNodeCompact { - /// The bitmask indicating the presence of children at the respective nibble positions in the - /// trie. If the bit at position i (counting from the right) is set (1), it indicates that a - /// child exists for the nibble value i. If the bit is unset (0), it means there is no child - /// for that nibble value. - pub state_mask: TrieMask, - /// The bitmask representing the internal (unhashed) children at the - /// respective nibble positions in the trie. If the bit at position `i` (counting from the - /// right) is set (1) and also present in the state_mask, it indicates that the - /// corresponding child at the nibble value `i` is an internal child. If the bit is unset - /// (0), it means the child is not an internal child. - pub tree_mask: TrieMask, - /// The bitmask representing the hashed children at the respective nibble - /// positions in the trie. If the bit at position `i` (counting from the right) is set (1) and - /// also present in the state_mask, it indicates that the corresponding child at the nibble - /// value `i` is a hashed child. If the bit is unset (0), it means the child is not a - /// hashed child. - pub hash_mask: TrieMask, - /// Collection of hashes associated with the children of the branch node. - /// Each child hash is calculated by hashing two consecutive sub-branch roots. - pub hashes: Vec, - /// An optional root hash of the subtree rooted at this branch node. - pub root_hash: Option, -} - -impl BranchNodeCompact { - /// Creates a new [BranchNodeCompact] from the given parameters. - pub fn new( - state_mask: impl Into, - tree_mask: impl Into, - hash_mask: impl Into, - hashes: Vec, - root_hash: Option, - ) -> Self { - let (state_mask, tree_mask, hash_mask) = - (state_mask.into(), tree_mask.into(), hash_mask.into()); - assert!(tree_mask.is_subset_of(state_mask)); - assert!(hash_mask.is_subset_of(state_mask)); - assert_eq!(hash_mask.count_ones() as usize, hashes.len()); - Self { state_mask, tree_mask, hash_mask, hashes, root_hash } - } - - /// Returns the hash associated with the given nibble. - pub fn hash_for_nibble(&self, nibble: u8) -> B256 { - let mask = *TrieMask::from_nibble(nibble) - 1; - let index = (*self.hash_mask & mask).count_ones(); - self.hashes[index as usize] - } -} +/// Wrapper around `BranchNodeCompact` that implements `Compact`. +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct StoredBranchNode(pub BranchNodeCompact); -impl Compact for BranchNodeCompact { +impl Compact for StoredBranchNode { fn to_compact(self, buf: &mut B) -> usize where B: bytes::BufMut + AsMut<[u8]>, { - let BranchNodeCompact { state_mask, tree_mask, hash_mask, root_hash, hashes } = self; + let BranchNodeCompact { state_mask, tree_mask, hash_mask, root_hash, hashes } = self.0; let mut buf_size = 0; - buf_size += state_mask.to_compact(buf); - buf_size += tree_mask.to_compact(buf); - buf_size += hash_mask.to_compact(buf); + buf_size += StoredTrieMask(state_mask).to_compact(buf); + buf_size += StoredTrieMask(tree_mask).to_compact(buf); + buf_size += StoredTrieMask(hash_mask).to_compact(buf); if let Some(root_hash) = root_hash { buf_size += B256::len_bytes(); @@ -170,9 +42,9 @@ impl Compact for BranchNodeCompact { assert_eq!(buf.len() % hash_len, 6); // Consume the masks. - let (state_mask, buf) = TrieMask::from_compact(buf, 0); - let (tree_mask, buf) = TrieMask::from_compact(buf, 0); - let (hash_mask, buf) = TrieMask::from_compact(buf, 0); + let (StoredTrieMask(state_mask), buf) = StoredTrieMask::from_compact(buf, 0); + let (StoredTrieMask(tree_mask), buf) = StoredTrieMask::from_compact(buf, 0); + let (StoredTrieMask(hash_mask), buf) = StoredTrieMask::from_compact(buf, 0); let mut buf = buf; let mut num_hashes = buf.len() / hash_len; @@ -192,14 +64,14 @@ impl Compact for BranchNodeCompact { buf.advance(hash_len); } - (Self::new(state_mask, tree_mask, hash_mask, hashes, root_hash), buf) + (Self(BranchNodeCompact::new(state_mask, tree_mask, hash_mask, hashes, root_hash)), buf) } } #[cfg(test)] mod tests { use super::*; - use crate::hex_literal::hex; + use alloy_primitives::hex; #[test] fn node_encoding() { @@ -215,7 +87,7 @@ mod tests { ); let mut out = Vec::new(); - let compact_len = BranchNodeCompact::to_compact(n.clone(), &mut out); - assert_eq!(BranchNodeCompact::from_compact(&out, compact_len).0, n); + let compact_len = StoredBranchNode(n.clone()).to_compact(&mut out); + assert_eq!(StoredBranchNode::from_compact(&out, compact_len).0 .0, n); } } diff --git a/crates/primitives/src/trie/nodes/extension.rs b/crates/primitives/src/trie/nodes/extension.rs deleted file mode 100644 index 35233fdffa0d..000000000000 --- a/crates/primitives/src/trie/nodes/extension.rs +++ /dev/null @@ -1,53 +0,0 @@ -use super::{super::Nibbles, rlp_node}; -use alloy_rlp::{BufMut, Encodable}; -use smallvec::SmallVec; - -/// An intermediate node that exists solely to compress the trie's paths. It contains a path segment -/// (a shared prefix of keys) and a single child pointer. Essentially, an extension node can be -/// thought of as a shortcut within the trie to reduce its overall depth. -/// -/// The purpose of an extension node is to optimize the trie structure by collapsing multiple nodes -/// with a single child into one node. This simplification reduces the space and computational -/// complexity when performing operations on the trie. -pub struct ExtensionNode<'a> { - /// A common prefix for keys. See [`Nibbles::encode_path_leaf`] for more information. - pub prefix: SmallVec<[u8; 36]>, - /// A pointer to the child. - pub node: &'a [u8], -} - -impl<'a> ExtensionNode<'a> { - /// Creates a new extension node with the given prefix and child. - pub fn new(prefix: &Nibbles, node: &'a [u8]) -> Self { - Self { prefix: prefix.encode_path_leaf(false), node } - } - - /// RLP encodes the node and returns either RLP(Node) or RLP(keccak(RLP(node))). - pub fn rlp(&self, buf: &mut Vec) -> Vec { - self.encode(buf); - rlp_node(buf) - } -} - -impl Encodable for ExtensionNode<'_> { - fn encode(&self, out: &mut dyn BufMut) { - let h = alloy_rlp::Header { - list: true, - payload_length: self.prefix.as_slice().length() + self.node.len(), - }; - h.encode(out); - // Slices have different RLP encoding from Vectors so we need to `as_slice() - self.prefix.as_slice().encode(out); - // The nodes are already RLP encoded - out.put_slice(self.node); - } -} - -impl std::fmt::Debug for ExtensionNode<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ExtensionNode") - .field("prefix", &crate::hex::encode(&self.prefix)) - .field("node", &crate::hex::encode(self.node)) - .finish() - } -} diff --git a/crates/primitives/src/trie/nodes/leaf.rs b/crates/primitives/src/trie/nodes/leaf.rs deleted file mode 100644 index 3de18de81d1f..000000000000 --- a/crates/primitives/src/trie/nodes/leaf.rs +++ /dev/null @@ -1,76 +0,0 @@ -use super::{super::Nibbles, rlp_node}; -use alloy_rlp::{BufMut, Encodable}; -use smallvec::SmallVec; - -/// A leaf node represents the endpoint or terminal node in the trie. In other words, a leaf node is -/// where actual values are stored. -/// -/// A leaf node consists of two parts: the key (or path) and the value. The key is typically the -/// remaining portion of the key after following the path through the trie, and the value is the -/// data associated with the full key. When searching the trie for a specific key, reaching a leaf -/// node means that the search has successfully found the value associated with that key. -#[derive(Default)] -pub struct LeafNode<'a> { - /// The key path. See [`Nibbles::encode_path_leaf`] for more information. - pub key: SmallVec<[u8; 36]>, - /// The node value. - pub value: &'a [u8], -} - -impl<'a> LeafNode<'a> { - /// Creates a new leaf node with the given key and value. - pub fn new(key: &Nibbles, value: &'a [u8]) -> Self { - Self { key: key.encode_path_leaf(true), value } - } - - /// RLP encodes the node and returns either RLP(Node) or RLP(keccak(RLP(node))) - /// depending on if the serialized node was longer than a keccak). - pub fn rlp(&self, out: &mut Vec) -> Vec { - self.encode(out); - rlp_node(out) - } -} - -// Handroll because `key` must be encoded as a slice -impl Encodable for LeafNode<'_> { - fn encode(&self, out: &mut dyn BufMut) { - #[derive(alloy_rlp::RlpEncodable)] - struct S<'a> { - encoded_path: &'a [u8], - value: &'a [u8], - } - S { encoded_path: &self.key, value: self.value }.encode(out); - } -} - -impl std::fmt::Debug for LeafNode<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("LeafNode") - .field("key", &crate::hex::encode(&self.key)) - .field("value", &crate::hex::encode(self.value)) - .finish() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::hex; - - // From manual regression test - #[test] - fn encode_leaf_node_nibble() { - let nibble = Nibbles::from_nibbles_unchecked(hex!("0604060f")); - let encoded = nibble.encode_path_leaf(true); - assert_eq!(encoded[..], hex!("20646f")); - } - - #[test] - fn rlp_leaf_node_roundtrip() { - let nibble = Nibbles::from_nibbles_unchecked(hex!("0604060f")); - let val = hex!("76657262"); - let leaf = LeafNode::new(&nibble, &val); - let rlp = leaf.rlp(&mut vec![]); - assert_eq!(rlp, hex!("c98320646f8476657262")); - } -} diff --git a/crates/primitives/src/trie/nodes/mod.rs b/crates/primitives/src/trie/nodes/mod.rs index c0c661795d19..f3db93f3e7e8 100644 --- a/crates/primitives/src/trie/nodes/mod.rs +++ b/crates/primitives/src/trie/nodes/mod.rs @@ -1,36 +1,6 @@ -use crate::{keccak256, B256}; -use alloy_rlp::EMPTY_STRING_CODE; -use std::ops::Range; +//! Various branch nodes produced by the hash builder. mod branch; -pub use branch::{BranchNode, BranchNodeCompact}; +pub use branch::StoredBranchNode; -mod extension; -pub use extension::ExtensionNode; - -mod leaf; -pub use leaf::LeafNode; - -/// The range of valid child indexes. -pub const CHILD_INDEX_RANGE: Range = 0..16; - -/// Given an RLP encoded node, returns either RLP(node) or RLP(keccak(RLP(node))) -#[inline] -fn rlp_node(rlp: &[u8]) -> Vec { - if rlp.len() < B256::len_bytes() { - rlp.to_vec() - } else { - word_rlp(&keccak256(rlp)) - } -} - -/// Optimization for quick encoding of a 32-byte word as RLP. -// TODO: this could return [u8; 33] but Vec is needed everywhere this function is used -#[inline] -pub fn word_rlp(word: &B256) -> Vec { - // Gets optimized to alloc + write directly into it: https://godbolt.org/z/rfWGG6ebq - let mut arr = [0; 33]; - arr[0] = EMPTY_STRING_CODE + 32; - arr[1..].copy_from_slice(word.as_slice()); - arr.to_vec() -} +pub use alloy_trie::nodes::*; diff --git a/crates/primitives/src/trie/proofs.rs b/crates/primitives/src/trie/proofs.rs index f603c07dcd30..094f4d29df31 100644 --- a/crates/primitives/src/trie/proofs.rs +++ b/crates/primitives/src/trie/proofs.rs @@ -1,3 +1,5 @@ +//! Merkle trie proofs. + use super::Nibbles; use crate::{keccak256, Account, Address, Bytes, B256, U256}; diff --git a/crates/primitives/src/trie/storage.rs b/crates/primitives/src/trie/storage.rs index 33f68fc05d1b..04ff57e1f31c 100644 --- a/crates/primitives/src/trie/storage.rs +++ b/crates/primitives/src/trie/storage.rs @@ -1,4 +1,4 @@ -use super::{BranchNodeCompact, StoredNibblesSubKey}; +use super::{BranchNodeCompact, StoredBranchNode, StoredNibblesSubKey}; use reth_codecs::Compact; use serde::{Deserialize, Serialize}; @@ -20,14 +20,14 @@ impl Compact for StorageTrieEntry { B: bytes::BufMut + AsMut<[u8]>, { let nibbles_len = self.nibbles.to_compact(buf); - let node_len = self.node.to_compact(buf); + let node_len = StoredBranchNode(self.node).to_compact(buf); nibbles_len + node_len } fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { let (nibbles, buf) = StoredNibblesSubKey::from_compact(buf, 33); - let (node, buf) = BranchNodeCompact::from_compact(buf, len - 33); - let this = Self { nibbles, node }; + let (node, buf) = StoredBranchNode::from_compact(buf, len - 33); + let this = Self { nibbles, node: node.0 }; (this, buf) } } diff --git a/crates/primitives/src/trie/subnode.rs b/crates/primitives/src/trie/subnode.rs index e6976cf13a2b..94df21219d59 100644 --- a/crates/primitives/src/trie/subnode.rs +++ b/crates/primitives/src/trie/subnode.rs @@ -1,4 +1,4 @@ -use super::BranchNodeCompact; +use super::{BranchNodeCompact, StoredBranchNode}; use bytes::Buf; use reth_codecs::Compact; @@ -37,7 +37,7 @@ impl Compact for StoredSubNode { if let Some(node) = self.node { buf.put_u8(1); len += 1; - len += node.to_compact(buf); + len += StoredBranchNode(node).to_compact(buf); } else { len += 1; buf.put_u8(0); @@ -56,9 +56,9 @@ impl Compact for StoredSubNode { let node_exsists = buf.get_u8() != 0; let node = if node_exsists { - let (node, rest) = BranchNodeCompact::from_compact(buf, 0); + let (node, rest) = StoredBranchNode::from_compact(buf, 0); buf = rest; - Some(node) + Some(node.0) } else { None }; diff --git a/crates/storage/db/src/tables/codecs/compact.rs b/crates/storage/db/src/tables/codecs/compact.rs index bcbdb2b1eb30..f31e61026e65 100644 --- a/crates/storage/db/src/tables/codecs/compact.rs +++ b/crates/storage/db/src/tables/codecs/compact.rs @@ -35,7 +35,7 @@ impl_compression_for_compact!( Receipt, TxType, StorageEntry, - BranchNodeCompact, + StoredBranchNode, StoredNibbles, StoredNibblesSubKey, StorageTrieEntry, diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index dc19a406a96b..337554866c07 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -36,7 +36,7 @@ use crate::{ }; use reth_primitives::{ stage::StageCheckpoint, - trie::{BranchNodeCompact, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey}, + trie::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey}, Account, Address, BlockHash, BlockNumber, Bytecode, Header, IntegerList, PruneCheckpoint, PruneSegment, Receipt, StorageEntry, TransactionSignedNoHash, TxHash, TxNumber, B256, }; @@ -421,7 +421,7 @@ dupsort!( table!( /// Stores the current state's Merkle Patricia Tree. - ( AccountsTrie ) StoredNibbles | BranchNodeCompact + ( AccountsTrie ) StoredNibbles | StoredBranchNode ); dupsort!( diff --git a/crates/trie/src/trie.rs b/crates/trie/src/trie.rs index 7ef189cf67fe..d58fcd51fc64 100644 --- a/crates/trie/src/trie.rs +++ b/crates/trie/src/trie.rs @@ -1179,7 +1179,7 @@ mod tests { .into_iter() .map(|item| { let (key, node) = item.unwrap(); - (key.0, node) + (key.0, node.0) }) .collect(); assert_trie_updates(&account_updates); diff --git a/crates/trie/src/trie_cursor/database_cursors.rs b/crates/trie/src/trie_cursor/database_cursors.rs index 2b8484fe3556..317285cd33db 100644 --- a/crates/trie/src/trie_cursor/database_cursors.rs +++ b/crates/trie/src/trie_cursor/database_cursors.rs @@ -51,14 +51,14 @@ where &mut self, key: Self::Key, ) -> Result, BranchNodeCompact)>, DatabaseError> { - Ok(self.0.seek_exact(key)?.map(|value| (value.0 .0.to_vec(), value.1))) + Ok(self.0.seek_exact(key)?.map(|value| (value.0 .0.to_vec(), value.1 .0))) } fn seek( &mut self, key: Self::Key, ) -> Result, BranchNodeCompact)>, DatabaseError> { - Ok(self.0.seek(key)?.map(|value| (value.0 .0.to_vec(), value.1))) + Ok(self.0.seek(key)?.map(|value| (value.0 .0.to_vec(), value.1 .0))) } fn current(&mut self) -> Result, DatabaseError> { @@ -123,7 +123,7 @@ mod tests { }; use reth_primitives::{ hex_literal::hex, - trie::{BranchNodeCompact, StorageTrieEntry}, + trie::{BranchNodeCompact, StorageTrieEntry, StoredBranchNode}, }; use reth_provider::test_utils::create_test_provider_factory; @@ -144,13 +144,13 @@ mod tests { cursor .upsert( key.into(), - BranchNodeCompact::new( + StoredBranchNode(BranchNodeCompact::new( 0b0000_0010_0000_0001, 0b0000_0010_0000_0001, 0, Vec::default(), None, - ), + )), ) .unwrap(); } diff --git a/crates/trie/src/updates.rs b/crates/trie/src/updates.rs index 9d7bfcbb31a0..1836e222df65 100644 --- a/crates/trie/src/updates.rs +++ b/crates/trie/src/updates.rs @@ -5,7 +5,10 @@ use reth_db::{ transaction::{DbTx, DbTxMut}, }; use reth_primitives::{ - trie::{BranchNodeCompact, Nibbles, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey}, + trie::{ + BranchNodeCompact, Nibbles, StorageTrieEntry, StoredBranchNode, StoredNibbles, + StoredNibblesSubKey, + }, B256, }; use std::collections::{hash_map::IntoIter, HashMap}; @@ -122,7 +125,7 @@ impl TrieUpdates { } TrieOp::Update(node) => { if !nibbles.0.is_empty() { - account_trie_cursor.upsert(nibbles, node)?; + account_trie_cursor.upsert(nibbles, StoredBranchNode(node))?; } } }, diff --git a/crates/trie/src/walker.rs b/crates/trie/src/walker.rs index 9f80459d790f..b253e19f9508 100644 --- a/crates/trie/src/walker.rs +++ b/crates/trie/src/walker.rs @@ -253,7 +253,7 @@ mod tests { trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor}, }; use reth_db::{cursor::DbCursorRW, tables, transaction::DbTxMut}; - use reth_primitives::trie::StorageTrieEntry; + use reth_primitives::trie::{StorageTrieEntry, StoredBranchNode}; use reth_provider::test_utils::create_test_provider_factory; #[test] @@ -284,7 +284,7 @@ mod tests { let mut account_cursor = tx.tx_ref().cursor_write::().unwrap(); for (k, v) in &inputs { - account_cursor.upsert(k.clone().into(), v.clone()).unwrap(); + account_cursor.upsert(k.clone().into(), StoredBranchNode(v.clone())).unwrap(); } let account_trie = DatabaseAccountTrieCursor::new(account_cursor); test_cursor(account_trie, &expected);