chore(primitives): extract trie HashBuilder implementation (#5832)

This commit is contained in:
DaniPopes
2023-12-26 09:48:55 +02:00
committed by GitHub
parent 7b0ecceafb
commit cbf6324594
21 changed files with 264 additions and 1267 deletions

233
Cargo.lock generated
View File

@@ -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]]

View File

@@ -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",

View File

@@ -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<Vec<u8>>,
value: HashBuilderValue,
groups: Vec<TrieMask>,
tree_masks: Vec<TrieMask>,
hash_masks: Vec<TrieMask>,
stored_in_database: bool,
updated_branch_nodes: Option<HashMap<Nibbles, BranchNodeCompact>>,
proof_retainer: Option<ProofRetainer>,
rlp_buf: Vec<u8>,
}
impl From<HashBuilderState> 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<HashBuilder> 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<Nibbles>) -> 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<Nibbles, BranchNodeCompact>) {
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<Nibbles, Bytes> {
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<T: Into<HashBuilderValue>>(&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(&current);
}
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(&current, 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(&current.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(&current, len);
// Need to store the branch node in an efficient format
// outside of the hash builder
self.store_branch_node(&current, 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<B256> {
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(&current.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<B256>) {
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<I, K, V>(iter: I) -> B256
where
I: IntoIterator<Item = (K, V)>,
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::<KeccakHasher, _, _, _>(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<Item = (K, &'a U256)>,
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::<BTreeMap<_, _>>();
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<I, K, V>(iter: I)
where
I: Iterator<Item = (K, V)>,
K: AsRef<[u8]> + Ord,
V: AsRef<[u8]>,
{
let mut hb = HashBuilder::default();
let data = iter.collect::<BTreeMap<_, _>>();
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<B256, U256>)| {
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::<Vec<_>>();
// 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::*;

View File

@@ -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<Nibbles>,
/// The map of retained proofs (RLP serialized trie nodes)
/// with their corresponding key in the trie.
proofs: BTreeMap<Nibbles, Bytes>,
}
impl ProofRetainer {
/// Create new retainer with target nibbles.
pub fn new(targets: Vec<Nibbles>) -> 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<Nibbles, Bytes> {
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()));
}
}
}

View File

@@ -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<HashBuilderState> 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<HashBuilder> 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<B>(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;
}

View File

@@ -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<u8>),
}
/// 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<B>(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<Vec<u8>> for HashBuilderValue {
fn from(value: Vec<u8>) -> Self {
Self::Bytes(value)
}
}
impl From<&[u8]> for HashBuilderValue {
fn from(value: &[u8]) -> Self {
Self::Bytes(value.to_vec())
}
}
impl From<B256> for HashBuilderValue {
fn from(value: B256) -> Self {
Self::Hash(value)
}
}
impl Default for HashBuilderValue {
fn default() -> Self {
Self::Bytes(vec![])
}
}

View File

@@ -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<B>(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)
}
}

View File

@@ -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 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 account;
mod mask;
mod nibbles;
mod storage;
mod subnode;
pub use storage::StorageTrieEntry;
pub use self::{
account::TrieAccount,
mask::TrieMask,
nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey},
storage::StorageTrieEntry,
subnode::StoredSubNode,
};
mod subnode;
pub use subnode::StoredSubNode;
pub use alloy_trie::{BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH};

View File

@@ -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<u8>],
}
/// Wrapper around `BranchNodeCompact` that implements `Compact`.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StoredBranchNode(pub BranchNodeCompact);
impl<'a> BranchNode<'a> {
/// Create a new branch node from the stack of nodes.
pub fn new(stack: &'a [Vec<u8>]) -> 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<Item = B256> + '_ {
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<u8>) -> Vec<u8> {
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<B256>,
/// An optional root hash of the subtree rooted at this branch node.
pub root_hash: Option<B256>,
}
impl BranchNodeCompact {
/// Creates a new [BranchNodeCompact] from the given parameters.
pub fn new(
state_mask: impl Into<TrieMask>,
tree_mask: impl Into<TrieMask>,
hash_mask: impl Into<TrieMask>,
hashes: Vec<B256>,
root_hash: Option<B256>,
) -> 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]
}
}
impl Compact for BranchNodeCompact {
impl Compact for StoredBranchNode {
fn to_compact<B>(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);
}
}

View File

@@ -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<u8>) -> Vec<u8> {
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()
}
}

View File

@@ -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<u8>) -> Vec<u8> {
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"));
}
}

View File

@@ -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<u8> = 0..16;
/// Given an RLP encoded node, returns either RLP(node) or RLP(keccak(RLP(node)))
#[inline]
fn rlp_node(rlp: &[u8]) -> Vec<u8> {
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<u8> {
// 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::*;

View File

@@ -1,3 +1,5 @@
//! Merkle trie proofs.
use super::Nibbles;
use crate::{keccak256, Account, Address, Bytes, B256, U256};

View File

@@ -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)
}
}

View File

@@ -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
};

View File

@@ -35,7 +35,7 @@ impl_compression_for_compact!(
Receipt,
TxType,
StorageEntry,
BranchNodeCompact,
StoredBranchNode,
StoredNibbles,
StoredNibblesSubKey,
StorageTrieEntry,

View File

@@ -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!(

View File

@@ -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);

View File

@@ -51,14 +51,14 @@ where
&mut self,
key: Self::Key,
) -> Result<Option<(Vec<u8>, 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<Option<(Vec<u8>, 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<Option<TrieKey>, 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();
}

View File

@@ -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))?;
}
}
},

View File

@@ -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::<tables::AccountsTrie>().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);